From 3f3fa589eb16f05d89b5b99d4569bdc3dca71efe Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 17 Nov 2025 20:07:49 +0100 Subject: [PATCH 01/57] Adjust headings in generated API reports --- .../java/org/junit/api/tools/AbstractApiReportWriter.java | 8 ++++---- .../java/org/junit/api/tools/AsciidocApiReportWriter.java | 8 ++++---- .../java/org/junit/api/tools/HtmlApiReportWriter.java | 8 ++++---- .../java/org/junit/api/tools/MarkdownApiReportWriter.java | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/documentation/src/tools/java/org/junit/api/tools/AbstractApiReportWriter.java b/documentation/src/tools/java/org/junit/api/tools/AbstractApiReportWriter.java index 5d2526b03f49..1943b3e7865f 100644 --- a/documentation/src/tools/java/org/junit/api/tools/AbstractApiReportWriter.java +++ b/documentation/src/tools/java/org/junit/api/tools/AbstractApiReportWriter.java @@ -60,12 +60,12 @@ protected void printDeclarationSection(Set statuses, Status status, List return; } declarationsByModule.forEach((moduleName, moduleDeclarations) -> { - out.println(h4("Module " + moduleName)); + out.println(h3("Module " + moduleName)); out.println(); moduleDeclarations.stream() // .collect(groupingBy(Declaration::packageName, TreeMap::new, toList())) // .forEach((packageName, packageDeclarations) -> { - out.println(h5("Package " + packageName)); + out.println(h4("Package " + packageName)); out.println(); printDeclarationTableHeader(out); packageDeclarations.forEach(it -> printDeclarationTableRow(it, out)); @@ -92,9 +92,9 @@ protected void printDeclarationSectionHeader(Set statuses, Status status protected abstract String h2(String header); - protected abstract String h4(String header); + protected abstract String h3(String header); - protected abstract String h5(String header); + protected abstract String h4(String header); protected abstract String code(String element); diff --git a/documentation/src/tools/java/org/junit/api/tools/AsciidocApiReportWriter.java b/documentation/src/tools/java/org/junit/api/tools/AsciidocApiReportWriter.java index 0a285d3ffdea..59fe54b90154 100644 --- a/documentation/src/tools/java/org/junit/api/tools/AsciidocApiReportWriter.java +++ b/documentation/src/tools/java/org/junit/api/tools/AsciidocApiReportWriter.java @@ -34,13 +34,13 @@ protected String h2(String header) { } @Override - protected String h4(String header) { - return "[discrete]%n==== %s".formatted(header); + protected String h3(String header) { + return "%n=== %s".formatted(header); } @Override - protected String h5(String header) { - return "[discrete]%n===== %s".formatted(header); + protected String h4(String header) { + return "%n==== %s".formatted(header); } @Override diff --git a/documentation/src/tools/java/org/junit/api/tools/HtmlApiReportWriter.java b/documentation/src/tools/java/org/junit/api/tools/HtmlApiReportWriter.java index c0f5a237b00a..8b2cfc5870ea 100644 --- a/documentation/src/tools/java/org/junit/api/tools/HtmlApiReportWriter.java +++ b/documentation/src/tools/java/org/junit/api/tools/HtmlApiReportWriter.java @@ -35,13 +35,13 @@ protected String h2(String header) { } @Override - protected String h4(String header) { - return "

" + header + "

"; + protected String h3(String header) { + return "

" + header + "

"; } @Override - protected String h5(String header) { - return "
" + header + "
"; + protected String h4(String header) { + return "

" + header + "

"; } @Override diff --git a/documentation/src/tools/java/org/junit/api/tools/MarkdownApiReportWriter.java b/documentation/src/tools/java/org/junit/api/tools/MarkdownApiReportWriter.java index 458d6c721e8a..26ff3c38e4d5 100644 --- a/documentation/src/tools/java/org/junit/api/tools/MarkdownApiReportWriter.java +++ b/documentation/src/tools/java/org/junit/api/tools/MarkdownApiReportWriter.java @@ -35,13 +35,13 @@ protected String h2(String header) { } @Override - protected String h4(String header) { - return "#### " + header; + protected String h3(String header) { + return "### " + header; } @Override - protected String h5(String header) { - return "##### " + header; + protected String h4(String header) { + return "#### " + header; } @Override From 1b4b92ed71738229f0fa3c2d6d75162b62c3b60e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 17 Nov 2025 20:12:00 +0100 Subject: [PATCH 02/57] Set up Antora module --- documentation/antora.yml | 24 ++++++++++++++++++++++ documentation/documentation.gradle.kts | 28 ++++++++++++++++++++++++-- documentation/modules/ROOT/nav.adoc | 0 gradle/libs.versions.toml | 1 + 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 documentation/antora.yml create mode 100644 documentation/modules/ROOT/nav.adoc diff --git a/documentation/antora.yml b/documentation/antora.yml new file mode 100644 index 000000000000..5abd0da10059 --- /dev/null +++ b/documentation/antora.yml @@ -0,0 +1,24 @@ +name: junit +version: null +title: JUnit +nav: + - modules/ROOT/nav.adoc +ext: + collector: + run: + command: gradlew --quiet :documentation:generateAntoraResources + local: true + scan: + - dir: ./build/generated-antora-resources + clean: true + - dir: ./build/docs/fixedJavadoc + clean: true + into: modules/ROOT/attachments/api + - dir: ./src/test + into: modules/ROOT/examples + - dir: ./build/generated/asciidoc + clean: true + into: modules/ROOT/partials + - dir: ./build/plantuml + clean: true + into: modules/ROOT/images diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index 5697d44144eb..77e48ec7b6c7 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -15,6 +15,7 @@ plugins { alias(libs.plugins.asciidoctorPdf) alias(libs.plugins.gitPublish) alias(libs.plugins.plantuml) + alias(libs.plugins.spring.antora) id("junitbuild.build-parameters") id("junitbuild.kotlin-library-conventions") id("junitbuild.testing-conventions") @@ -270,8 +271,8 @@ tasks { val plantUmlOutputDirectory = plantUml.flatMap { it.outputDirectory } - withType().configureEach { - inputs.files( + val generateAsciidocInputs by registering { + dependsOn( generateConsoleLauncherOptions, generateConsoleLauncherDiscoverOptions, generateConsoleLauncherExecuteOptions, @@ -280,6 +281,10 @@ tasks { generateStandaloneConsoleLauncherShadowedArtifactsFile, plantUmlOutputDirectory ) + } + + withType().configureEach { + dependsOn(generateAsciidocInputs) resources { from(sourceDir) { @@ -550,4 +555,23 @@ tasks { into(layout.buildDirectory.dir("attestation")) rename("(.*)-SNAPSHOT.jar", "$1-SNAPSHOT+${buildRevision.substring(0, 7)}.jar") } + + generateAntoraYml { + asciidocAttributes.putAll(provider { + mapOf( + "version" to project.version, + "junit4-version" to libs.versions.junit4.get(), + "apiguardian-version" to libs.versions.apiguardian.get(), + "ota4j-version" to libs.versions.opentest4j.get(), + "surefire-version" to libs.versions.surefire.get(), + "release-branch" to releaseBranch, + "docs-version" to docsVersion, + "jdk-javadoc-base-url" to jdkJavadocBaseUrl + ) + }) + } + + register("generateAntoraResources") { + dependsOn(generateAntoraYml, generateAsciidocInputs, fixJavadoc) + } } diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a9c2814afe1..0e14db1aa89f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -111,3 +111,4 @@ nullaway = { id = "net.ltgt.nullaway", version = "2.3.0" } plantuml = { id = "io.freefair.plantuml", version = "9.1.0" } shadow = { id = "com.gradleup.shadow", version = "9.3.0" } spotless = { id = "com.diffplug.spotless", version = "8.1.0" } +spring-antora = { id = "io.spring.antora.generate-antora-yml", version = "0.0.1" } From 58b94a4d550e31504d0cc2c87e433cf1c7c21fea Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 23 Nov 2025 19:04:06 +0100 Subject: [PATCH 03/57] Add task to build Antora site locally --- .gitignore | 3 ++ documentation/antora-playbook.yml | 26 +++++++++++++ documentation/documentation.gradle.kts | 38 +++++++++++++++++++ documentation/package.json | 12 ++++++ gradle/libs.versions.toml | 1 + .../junitbuild.checkstyle-nohttp.gradle.kts | 1 + settings.gradle.kts | 1 - 7 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 documentation/antora-playbook.yml create mode 100644 documentation/package.json diff --git a/.gitignore b/.gitignore index 2ff2b321ef5c..2f03fe1f2adc 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ checksums* # snapshot-tests *.snapshot_actual *.snapshot_raw + +# Antora +/documentation/node_modules/ diff --git a/documentation/antora-playbook.yml b/documentation/antora-playbook.yml new file mode 100644 index 000000000000..f371bf92c6f2 --- /dev/null +++ b/documentation/antora-playbook.yml @@ -0,0 +1,26 @@ +antora: + extensions: + - '@antora/collector-extension' + - '@antora/lunr-extension' + - require: '@springio/antora-extensions/root-component-extension' + root_component_name: junit + - require: '@springio/antora-extensions/root-attachments-extension' +site: + title: JUnit User Guide + url: https://docs.junit.org +content: + sources: + - url: @GIT_REPO_ROOT@ + branches: @GIT_BRANCH_NAME@ + start_path: documentation + worktrees: true +asciidoc: + attributes: + attribute-missing: warn +runtime: + log: + failure_level: warn +ui: + bundle: + url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable + snapshot: true diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index 77e48ec7b6c7..4a14b7d2d257 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -11,6 +11,7 @@ import org.gradle.api.tasks.PathSensitivity.RELATIVE import org.ysb33r.grolifant.api.core.jvm.ExecutionMode.JAVA_EXEC plugins { + alias(libs.plugins.antora) alias(libs.plugins.asciidoctorConvert) alias(libs.plugins.asciidoctorPdf) alias(libs.plugins.gitPublish) @@ -149,6 +150,15 @@ require(externalModulesWithoutModularJavadoc.values.all { it.endsWith("/") }) { "all base URLs must end with a trailing slash: $externalModulesWithoutModularJavadoc" } +repositories { + // Redefined here because the Node.js plugin adds a repo + mavenCentral() +} + +antora { + setOptions(mapOf("clean" to true, "stacktrace" to true, "fetch" to true)) +} + tasks { val consoleLauncherTestReportsDir = project.layout.buildDirectory.dir("console-launcher-test-results") @@ -574,4 +584,32 @@ tasks { register("generateAntoraResources") { dependsOn(generateAntoraYml, generateAsciidocInputs, fixJavadoc) } + + val generateAntoraPlaybook by registering(Copy::class) { + + val gitRepoRoot = providers.exec { + commandLine("git", "worktree", "list", "--porcelain", "-z") + }.standardOutput.asText.map { it.substringBefore('\u0000').substringAfter(' ') } + + val gitBranchName = providers.exec { + commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") + }.standardOutput.asText.map { it.trim() } + + from(layout.projectDirectory.file("antora-playbook.yml").asFile) + filter { line -> + var result = line + if (line.contains("@GIT_REPO_ROOT@")) { + result = result.replace("@GIT_REPO_ROOT@", gitRepoRoot.get()) + } + if (line.contains("@GIT_BRANCH_NAME@")) { + result = result.replace("@GIT_BRANCH_NAME@", gitBranchName.get()) + } + return@filter result + } + into(layout.buildDirectory.dir("antora")) + } + + project.antora { + playbook = generateAntoraPlaybook.map { it.rootSpec.destinationDir.resolve("antora-playbook.yml") } + } } diff --git a/documentation/package.json b/documentation/package.json new file mode 100644 index 000000000000..9960fe42e116 --- /dev/null +++ b/documentation/package.json @@ -0,0 +1,12 @@ +{ + "devDependencies": { + "@antora/cli": "3.1.14", + "@antora/site-generator": "3.1.14" + }, + "dependencies": { + "@antora/collector-extension": "1.0.2", + "@antora/lunr-extension": "1.0.0-alpha.10", + "@springio/antora-extensions": "1.14.7", + "highlight.js": "11.11.1" + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0e14db1aa89f..3f91c4f0bf69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -93,6 +93,7 @@ log4j = ["log4j-core", "log4j-jul"] xmlunit = ["xmlunit-assertj", "xmlunit-placeholders", "xmlunit-jakarta-jaxb-impl", "jaxb-api", "jaxb-runtime"] [plugins] +antora = { id = "org.antora", version = "1.0.0" } asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciidoctor-plugins" } asciidoctorPdf = { id = "org.asciidoctor.jvm.pdf", version.ref = "asciidoctor-plugins" } bnd = { id = "biz.aQute.bnd", version.ref = "bnd" } diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-nohttp.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-nohttp.gradle.kts index 74af245a3d47..2a2dc620c443 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-nohttp.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.checkstyle-nohttp.gradle.kts @@ -37,5 +37,6 @@ tasks.register("checkstyleNohttp") { exclude("**/*.jks") exclude("**/build/**") exclude("**/.kotlin") + exclude("**/node_modules/**") } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 22cff4977cde..590103aa62c4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,7 +17,6 @@ dependencyResolutionManagement { repositories { mavenCentral() } - repositoriesMode = FAIL_ON_PROJECT_REPOS } val buildParameters = the() From 843f074bbe3dae44ee25cc5f148dfea6656bdebc Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 23 Nov 2025 19:18:52 +0100 Subject: [PATCH 04/57] Extract conventions plugin --- documentation/documentation.gradle.kts | 44 ++----------------- gradle/libs.versions.toml | 1 + gradle/plugins/antora/build.gradle.kts | 23 ++++++++++ .../junitbuild.antora-conventions.gradle.kts | 44 +++++++++++++++++++ gradle/plugins/settings.gradle.kts | 1 + 5 files changed, 72 insertions(+), 41 deletions(-) create mode 100644 gradle/plugins/antora/build.gradle.kts create mode 100644 gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index 4a14b7d2d257..df85ee2979f0 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -11,12 +11,11 @@ import org.gradle.api.tasks.PathSensitivity.RELATIVE import org.ysb33r.grolifant.api.core.jvm.ExecutionMode.JAVA_EXEC plugins { - alias(libs.plugins.antora) alias(libs.plugins.asciidoctorConvert) alias(libs.plugins.asciidoctorPdf) alias(libs.plugins.gitPublish) alias(libs.plugins.plantuml) - alias(libs.plugins.spring.antora) + id("junitbuild.antora-conventions") id("junitbuild.build-parameters") id("junitbuild.kotlin-library-conventions") id("junitbuild.testing-conventions") @@ -150,15 +149,6 @@ require(externalModulesWithoutModularJavadoc.values.all { it.endsWith("/") }) { "all base URLs must end with a trailing slash: $externalModulesWithoutModularJavadoc" } -repositories { - // Redefined here because the Node.js plugin adds a repo - mavenCentral() -} - -antora { - setOptions(mapOf("clean" to true, "stacktrace" to true, "fetch" to true)) -} - tasks { val consoleLauncherTestReportsDir = project.layout.buildDirectory.dir("console-launcher-test-results") @@ -581,35 +571,7 @@ tasks { }) } - register("generateAntoraResources") { - dependsOn(generateAntoraYml, generateAsciidocInputs, fixJavadoc) - } - - val generateAntoraPlaybook by registering(Copy::class) { - - val gitRepoRoot = providers.exec { - commandLine("git", "worktree", "list", "--porcelain", "-z") - }.standardOutput.asText.map { it.substringBefore('\u0000').substringAfter(' ') } - - val gitBranchName = providers.exec { - commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") - }.standardOutput.asText.map { it.trim() } - - from(layout.projectDirectory.file("antora-playbook.yml").asFile) - filter { line -> - var result = line - if (line.contains("@GIT_REPO_ROOT@")) { - result = result.replace("@GIT_REPO_ROOT@", gitRepoRoot.get()) - } - if (line.contains("@GIT_BRANCH_NAME@")) { - result = result.replace("@GIT_BRANCH_NAME@", gitBranchName.get()) - } - return@filter result - } - into(layout.buildDirectory.dir("antora")) - } - - project.antora { - playbook = generateAntoraPlaybook.map { it.rootSpec.destinationDir.resolve("antora-playbook.yml") } + generateAntoraResources { + dependsOn(generateAsciidocInputs, fixJavadoc) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3f91c4f0bf69..e647c6cbc855 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,6 +108,7 @@ jmh = { id = "me.champeau.jmh", version = "0.7.3" } jreleaser = { id = "org.jreleaser", version = "1.21.0" } # check if workaround in gradle.properties can be removed when updating kotlin = { id = "org.jetbrains.kotlin.jvm", version = "2.2.21" } +node = { id = "com.github.node-gradle.node", version = "5.0.0" } nullaway = { id = "net.ltgt.nullaway", version = "2.3.0" } plantuml = { id = "io.freefair.plantuml", version = "9.1.0" } shadow = { id = "com.gradleup.shadow", version = "9.3.0" } diff --git a/gradle/plugins/antora/build.gradle.kts b/gradle/plugins/antora/build.gradle.kts new file mode 100644 index 000000000000..f6d134a2104d --- /dev/null +++ b/gradle/plugins/antora/build.gradle.kts @@ -0,0 +1,23 @@ +import junitbuild.extensions.markerCoordinates +import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21 + +plugins { + `kotlin-dsl` +} + +dependencies { + implementation(libs.plugins.antora.markerCoordinates) + implementation(libs.plugins.node.markerCoordinates) + implementation(libs.plugins.spring.antora.markerCoordinates) +} + +tasks.compileJava { + options.release = 21 +} + +kotlin { + compilerOptions { + jvmTarget = JVM_21 + freeCompilerArgs.add("-Xjdk-release=21") + } +} diff --git a/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts b/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts new file mode 100644 index 000000000000..969a50f1dc3c --- /dev/null +++ b/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts @@ -0,0 +1,44 @@ +import org.antora.gradle.AntoraExtension + +plugins { + id("org.antora") + id("io.spring.antora.generate-antora-yml") +} + +repositories { + // Redefined here because the Node.js plugin adds a repo + mavenCentral() +} + +tasks.register("generateAntoraResources") { + dependsOn("generateAntoraYml") +} + +val generateAntoraPlaybook by tasks.registering(Copy::class) { + + val gitRepoRoot = providers.exec { + commandLine("git", "worktree", "list", "--porcelain", "-z") + }.standardOutput.asText.map { it.substringBefore('\u0000').substringAfter(' ') } + + val gitBranchName = providers.exec { + commandLine("git", "rev-parse", "--abbrev-ref", "HEAD") + }.standardOutput.asText.map { it.trim() } + + from(layout.projectDirectory.file("antora-playbook.yml").asFile) + filter { line -> + var result = line + if (line.contains("@GIT_REPO_ROOT@")) { + result = result.replace("@GIT_REPO_ROOT@", gitRepoRoot.get()) + } + if (line.contains("@GIT_BRANCH_NAME@")) { + result = result.replace("@GIT_BRANCH_NAME@", gitBranchName.get()) + } + return@filter result + } + into(layout.buildDirectory.dir("antora")) +} + +the().apply { + setOptions(mapOf("clean" to true, "stacktrace" to true, "fetch" to true)) + playbook = generateAntoraPlaybook.map { it.rootSpec.destinationDir.resolve("antora-playbook.yml") } +} diff --git a/gradle/plugins/settings.gradle.kts b/gradle/plugins/settings.gradle.kts index b2ae97139041..2399fe456afc 100644 --- a/gradle/plugins/settings.gradle.kts +++ b/gradle/plugins/settings.gradle.kts @@ -19,6 +19,7 @@ dependencyResolutionManagement { rootProject.name = "plugins" +include("antora") include("backward-compatibility") include("build-parameters") include("common") From 74a2d7ed026514bc1df10cf4c47557ae8df7929a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 23 Nov 2025 19:37:01 +0100 Subject: [PATCH 05/57] Update README to reference Antora --- documentation/README.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/documentation/README.md b/documentation/README.md index acb46649d9d5..c0254882da92 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,10 +1,10 @@ # JUnit User Guide -This subproject contains the AsciiDoc sources for the JUnit User Guide. +This subproject contains the Antora/AsciiDoc sources for the JUnit User Guide. ## Structure -- `src/docs/asciidoc`: AsciiDoc files +- `modules/ROOT/pages`: AsciiDoc files - `src/test/java`: Java test source code that can be included in the AsciiDoc files - `src/test/kotlin`: Kotlin test source code that can be included in the AsciiDoc files - `src/test/resources`: Classpath resources that can be included in the AsciiDoc files or @@ -12,23 +12,14 @@ This subproject contains the AsciiDoc sources for the JUnit User Guide. ## Usage -### Generate AsciiDoc +### Generate Antora site This following Gradle command generates the HTML version of the User Guide as -`build/docs/asciidoc/user-guide/index.html`. +`build/antora/build/site`. ``` -./gradlew asciidoctor +./gradlew antora ``` On Linux operating systems, the `graphviz` package providing `/usr/bin/dot` must be -installed in order to generate the User Guide. - -### Generate AsciiDocPdf - -This following Gradle command generates the PDF version of the User Guide to -`build/docs/asciidocPdf/user-guide/index.pdf`. - -``` -./gradlew asciidoctorPdf -``` +installed in order to generate the PlantUML images used in the User Guide. From a586b4eb8c50ba43a260b01399f04a1f21dfde43 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 23 Nov 2025 19:40:55 +0100 Subject: [PATCH 06/57] Remove Asciidoctor plugins --- documentation/documentation.gradle.kts | 123 ------------------------- gradle/libs.versions.toml | 7 -- 2 files changed, 130 deletions(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index df85ee2979f0..fe3cd839c39d 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -5,14 +5,9 @@ import junitbuild.exec.RunConsoleLauncher import junitbuild.extensions.isSnapshot import junitbuild.extensions.javaModuleName import junitbuild.javadoc.ModuleSpecificJavadocFileOption -import org.asciidoctor.gradle.base.AsciidoctorAttributeProvider -import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask import org.gradle.api.tasks.PathSensitivity.RELATIVE -import org.ysb33r.grolifant.api.core.jvm.ExecutionMode.JAVA_EXEC plugins { - alias(libs.plugins.asciidoctorConvert) - alias(libs.plugins.asciidoctorPdf) alias(libs.plugins.gitPublish) alias(libs.plugins.plantuml) id("junitbuild.antora-conventions") @@ -85,14 +80,6 @@ dependencies { standaloneConsoleLauncher(projects.junitPlatformConsoleStandalone) } -asciidoctorj { - setJrubyVersion(libs.versions.jruby) - modules { - pdf.version(libs.versions.asciidoctorj.pdf) - } - requires(file("src/docs/asciidoc/resources/themes/rouge_junit.rb")) -} - val buildRevision: String by rootProject.extra val snapshot = version.isSnapshot() val docsVersion = if (snapshot) "snapshot" else version @@ -283,104 +270,6 @@ tasks { ) } - withType().configureEach { - dependsOn(generateAsciidocInputs) - - resources { - from(sourceDir) { - include("**/images/**/*.png") - include("**/images/**/*.svg") - } - from(plantUmlOutputDirectory) { - into("user-guide/images") - } - } - - // Temporary workaround for https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/599 - inputs.dir(sourceDir).withPropertyName("sourceDir").withPathSensitivity(RELATIVE) - - attributeProviders += AsciidoctorAttributeProvider { - mapOf( - "version" to version, - "junit4-version" to libs.versions.junit4.get(), - "apiguardian-version" to libs.versions.apiguardian.get(), - "ota4j-version" to libs.versions.opentest4j.get(), - "surefire-version" to libs.versions.surefire.get(), - "release-branch" to releaseBranch, - "docs-version" to docsVersion, - "revnumber" to version, - "consoleLauncherOptionsFile" to consoleLauncherOptionsFile.get(), - "consoleLauncherDiscoverOptionsFile" to consoleLauncherDiscoverOptionsFile.get(), - "consoleLauncherExecuteOptionsFile" to consoleLauncherExecuteOptionsFile.get(), - "consoleLauncherEnginesOptionsFile" to consoleLauncherEnginesOptionsFile.get(), - "experimentalApisTableFile" to experimentalApisTableFile.get(), - "deprecatedApisTableFile" to deprecatedApisTableFile.get(), - "standaloneConsoleLauncherShadowedArtifactsFile" to standaloneConsoleLauncherShadowedArtifactsFile.get(), - "outdir" to outputDir.absolutePath, - "source-highlighter" to "rouge", - "rouge-style" to "junit", - "tabsize" to "4", - "toc" to "left", - "icons" to "font", - "sectanchors" to true, - "idprefix" to "", - "idseparator" to "-", - "jdk-javadoc-base-url" to jdkJavadocBaseUrl - ) - } - - sourceSets["test"].apply { - attributes(mapOf( - "testDir" to java.srcDirs.first(), - "testResourcesDir" to resources.srcDirs.first() - )) - inputs.dir(java.srcDirs.first()) - inputs.dir(resources.srcDirs.first()) - attributes(mapOf("kotlinTestDir" to kotlin.srcDirs.first())) - inputs.dir(kotlin.srcDirs.first()) - } - - jvm { - // To avoid warning, see https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/597 - jvmArgs( - "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", - "--add-opens", "java.base/java.io=ALL-UNNAMED" - ) - } - - notCompatibleWithConfigurationCache("https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/564") - } - - asciidoctor { - sources { - include("**/index.adoc") - } - resources { - from(sourceDir) { - include("tocbot-*/**") - } - } - attributes(mapOf( - "linkToPdf" to uploadPdfs, - "userGuidePdfFileName" to userGuidePdfFileName, - "releaseNotesUrl" to "../release-notes/index.html#release-notes" - )) - } - - asciidoctorPdf { - // Avoid classpath conflicts with other Gradle plugins (e.g. JReleaser) - // Avoid propagating apparent memory leaks in Asciidoctor/JRuby to Gradle daemon. - setExecutionMode(JAVA_EXEC) - jvm { - maxHeapSize = "512M" - } - sources { - include("user-guide/index.adoc") - } - copyAllResources() - attributes(mapOf("releaseNotesUrl" to "https://docs.junit.org/$docsVersion/release-notes/")) - } - val downloadJavadocElementLists by registering { outputs.cacheIf { true } outputs.dir(elementListsDir).withPropertyName("elementListsDir") @@ -502,20 +391,8 @@ tasks { } val prepareDocsForUploadToGhPages by registering(Copy::class) { - dependsOn(fixJavadoc, asciidoctor, asciidoctorPdf) outputs.dir(docsDir) - from(asciidoctor.map { it.outputDir }) { - include("user-guide/**") - include("release-notes/**") - include("tocbot-*/**") - } - if (uploadPdfs) { - from(asciidoctorPdf.map { it.outputDir }) { - include("**/*.pdf") - rename { userGuidePdfFileName } - } - } from(fixJavadoc.map { it.destinationDir }) { into("api") } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e647c6cbc855..6fd166447ed1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,6 @@ [versions] ant = "1.10.15" apiguardian = "1.1.2" -asciidoctorj-pdf = "2.3.23" -asciidoctor-plugins = "4.0.5" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.27.6" bnd = "7.1.0" checkstyle = "12.2.0" @@ -10,7 +8,6 @@ eclipse = "4.37.0" jackson = "2.20.1" jacoco = "0.8.14" jmh = "1.37" -jruby = "9.4.14.0" junit4 = "4.13.2" junit4Min = "4.12" ktlint = "1.8.0" @@ -79,10 +76,8 @@ testingAnnotations = { module = "com.gradle:develocity-testing-annotations", ver woodstox = { module = "com.fasterxml.woodstox:woodstox-core", version = "7.1.1" } # Only declared here so Dependabot knows when to update the referenced versions -asciidoctorj-pdf = { module = "org.asciidoctor:asciidoctorj-pdf", version.ref = "asciidoctorj-pdf" } eclipse-platform = { module = "org.eclipse.platform:org.eclipse.platform", version.ref = "eclipse" } jacoco = { module = "org.jacoco:jacoco", version.ref = "jacoco" } -jruby = { module = "org.jruby:jruby", version.ref = "jruby" } junit4-latest = { module = "junit:junit", version.ref = "junit4" } junit4-bundle = { module = "org.apache.servicemix.bundles:org.apache.servicemix.bundles.junit", version = "4.13.2_1" } ktlint-cli = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" } @@ -94,8 +89,6 @@ xmlunit = ["xmlunit-assertj", "xmlunit-placeholders", "xmlunit-jakarta-jaxb-impl [plugins] antora = { id = "org.antora", version = "1.0.0" } -asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciidoctor-plugins" } -asciidoctorPdf = { id = "org.asciidoctor.jvm.pdf", version.ref = "asciidoctor-plugins" } bnd = { id = "biz.aQute.bnd", version.ref = "bnd" } buildParameters = { id = "org.gradlex.build-parameters", version = "1.4.4" } commonCustomUserData = { id = "com.gradle.common-custom-user-data-gradle-plugin", version = "2.4.0" } From c76c6ab62d6ab53ad27d99fc7a321752b76eca32 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 23 Nov 2025 19:46:19 +0100 Subject: [PATCH 07/57] Remove git-publish plugin and corresponding GitHub Action steps --- .github/workflows/main.yml | 18 +------- documentation/documentation.gradle.kts | 62 -------------------------- gradle/libs.versions.toml | 1 - 3 files changed, 1 insertion(+), 80 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bf4d92714ec6..076d64c040af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -127,21 +127,5 @@ jobs: with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | - prepareDocsForUploadToGhPages \ + antora \ -Dscan.tag.Documentation - - name: Configure Git - shell: bash - run: | - git config --global user.name "JUnit Team" - git config --global user.email "team@junit.org" - - name: Upload Documentation - if: github.event_name == 'push' && github.repository == 'junit-team/junit-framework' && github.ref == 'refs/heads/main' - uses: ./.github/actions/run-gradle - with: - encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - arguments: | - gitPublishPush \ - -Dscan.tag.Documentation - env: - GIT_USERNAME: git - GIT_PASSWORD: ${{ secrets.JUNIT_BUILDS_GITHUB_TOKEN_DOCS_REPO }} diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index fe3cd839c39d..46348e9c5b01 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -8,7 +8,6 @@ import junitbuild.javadoc.ModuleSpecificJavadocFileOption import org.gradle.api.tasks.PathSensitivity.RELATIVE plugins { - alias(libs.plugins.gitPublish) alias(libs.plugins.plantuml) id("junitbuild.antora-conventions") id("junitbuild.build-parameters") @@ -91,30 +90,6 @@ val userGuidePdfFileName = "junit-user-guide-${version}.pdf" val ota4jDocVersion = libs.versions.opentest4j.map { if (it.isSnapshot()) "snapshot" else it }.get() val apiGuardianDocVersion = libs.versions.apiguardian.map { if (it.isSnapshot()) "snapshot" else it }.get() -gitPublish { - repoUri = "https://github.com/junit-team/docs.junit.org.git" - - branch = "main" - sign = false - fetchDepth = 1 - - username = providers.environmentVariable("GIT_USERNAME") - password = providers.environmentVariable("GIT_PASSWORD") - - contents { - from(docsDir) - into(".") - } - - preserve { - include("**/*") - exclude("$docsVersion/**") - if (replaceCurrentDocs) { - exclude("current/**") - } - } -} - val generatedAsciiDocPath = layout.buildDirectory.dir("generated/asciidoc") val consoleLauncherOptionsFile = generatedAsciiDocPath.map { it.file("console-launcher-options.txt") } val consoleLauncherDiscoverOptionsFile = generatedAsciiDocPath.map { it.file("console-launcher-discover-options.txt") } @@ -390,43 +365,6 @@ tasks { into(layout.buildDirectory.dir("docs/fixedJavadoc")) } - val prepareDocsForUploadToGhPages by registering(Copy::class) { - outputs.dir(docsDir) - - from(fixJavadoc.map { it.destinationDir }) { - into("api") - } - into(docsDir.map { it.dir(docsVersion.toString()) }) - includeEmptyDirs = false - } - - val createCurrentDocsFolder by registering(Copy::class) { - dependsOn(prepareDocsForUploadToGhPages) - onlyIf { replaceCurrentDocs } - - from(docsDir.map { it.dir(docsVersion.toString()) }) - into(docsDir.map { it.dir("current") }) - } - - val configureGitAuthor by registering { - dependsOn(gitPublishReset) - doFirst { - File(gitPublish.repoDir.get().asFile, ".git/config").appendText(""" - [user] - name = JUnit Team - email = team@junit.org - """.trimIndent()) - } - } - - gitPublishCopy { - dependsOn(prepareDocsForUploadToGhPages, createCurrentDocsFolder) - } - - gitPublishCommit { - dependsOn(configureGitAuthor) - } - val prepareGitHubAttestation by registering(Sync::class) { from(attestationClasspath) into(layout.buildDirectory.dir("attestation")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6fd166447ed1..abe0b88fd124 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -96,7 +96,6 @@ develocity = { id = "com.gradle.develocity", version = "4.2.2" } download = { id = "de.undercouch.download", version = "5.6.0" } errorProne = { id = "net.ltgt.errorprone", version = "4.3.0" } foojayResolver = { id = "org.gradle.toolchains.foojay-resolver", version = "1.0.0" } -gitPublish = { id = "org.ajoberstar.git-publish", version = "5.1.3" } jmh = { id = "me.champeau.jmh", version = "0.7.3" } jreleaser = { id = "org.jreleaser", version = "1.21.0" } # check if workaround in gradle.properties can be removed when updating From fd01ffa00526486c316247cb303fed75e7c90c84 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 16:39:47 +0100 Subject: [PATCH 08/57] Use Node.js plugin directly --- documentation/.tool-versions | 1 + gradle/libs.versions.toml | 3 +- gradle/plugins/antora/build.gradle.kts | 2 +- .../junitbuild.antora-conventions.gradle.kts | 42 ++++++++++++++++--- .../plugins/build-parameters/build.gradle.kts | 6 +++ 5 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 documentation/.tool-versions diff --git a/documentation/.tool-versions b/documentation/.tool-versions new file mode 100644 index 000000000000..9d709112585c --- /dev/null +++ b/documentation/.tool-versions @@ -0,0 +1 @@ +nodejs 24.11.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index abe0b88fd124..6f06005720c2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,6 @@ log4j = ["log4j-core", "log4j-jul"] xmlunit = ["xmlunit-assertj", "xmlunit-placeholders", "xmlunit-jakarta-jaxb-impl", "jaxb-api", "jaxb-runtime"] [plugins] -antora = { id = "org.antora", version = "1.0.0" } bnd = { id = "biz.aQute.bnd", version.ref = "bnd" } buildParameters = { id = "org.gradlex.build-parameters", version = "1.4.4" } commonCustomUserData = { id = "com.gradle.common-custom-user-data-gradle-plugin", version = "2.4.0" } @@ -100,7 +99,7 @@ jmh = { id = "me.champeau.jmh", version = "0.7.3" } jreleaser = { id = "org.jreleaser", version = "1.21.0" } # check if workaround in gradle.properties can be removed when updating kotlin = { id = "org.jetbrains.kotlin.jvm", version = "2.2.21" } -node = { id = "com.github.node-gradle.node", version = "5.0.0" } +node = { id = "com.github.node-gradle.node", version = "7.1.0" } nullaway = { id = "net.ltgt.nullaway", version = "2.3.0" } plantuml = { id = "io.freefair.plantuml", version = "9.1.0" } shadow = { id = "com.gradleup.shadow", version = "9.3.0" } diff --git a/gradle/plugins/antora/build.gradle.kts b/gradle/plugins/antora/build.gradle.kts index f6d134a2104d..1e1dab1109c6 100644 --- a/gradle/plugins/antora/build.gradle.kts +++ b/gradle/plugins/antora/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } dependencies { - implementation(libs.plugins.antora.markerCoordinates) + implementation(projects.buildParameters) implementation(libs.plugins.node.markerCoordinates) implementation(libs.plugins.spring.antora.markerCoordinates) } diff --git a/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts b/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts index 969a50f1dc3c..6cf648dcfef3 100644 --- a/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts +++ b/gradle/plugins/antora/src/main/kotlin/junitbuild.antora-conventions.gradle.kts @@ -1,8 +1,9 @@ -import org.antora.gradle.AntoraExtension +import com.github.gradle.node.npm.task.NpxTask plugins { - id("org.antora") + id("com.github.node-gradle.node") id("io.spring.antora.generate-antora-yml") + id("junitbuild.build-parameters") } repositories { @@ -35,10 +36,39 @@ val generateAntoraPlaybook by tasks.registering(Copy::class) { } return@filter result } - into(layout.buildDirectory.dir("antora")) + into(layout.buildDirectory.dir("antora-playbook")) } -the().apply { - setOptions(mapOf("clean" to true, "stacktrace" to true, "fetch" to true)) - playbook = generateAntoraPlaybook.map { it.rootSpec.destinationDir.resolve("antora-playbook.yml") } +node { + download = buildParameters.antora.downloadNode + version = providers.fileContents(layout.projectDirectory.file(".tool-versions")).asText.map { + it.substringAfter("nodejs").trim() + } +} + +tasks.npmInstall { + args.addAll("--no-audit", "--no-package-lock", "--no-fund") +} + +tasks.register("antora") { + dependsOn(tasks.npmInstall) + description = "Runs Antora to generate a documentation site described by the playbook file." + + command = "antora" + args.addAll("--clean", "--stacktrace", "--fetch") + + args.add("--to-dir") + val outputDir = layout.buildDirectory.dir("antora-site") + args.add(outputDir.map { it.asFile.toRelativeString(layout.projectDirectory.asFile) }) + outputs.dir(outputDir) + + outputs.upToDateWhen { false } // not all inputs are tracked + + val playbook = generateAntoraPlaybook.map { it.rootSpec.destinationDir.resolve("antora-playbook.yml") } + args.add(playbook.map { it.toRelativeString(layout.projectDirectory.asFile) }) + inputs.file(playbook) + + doLast { + println("Antora site built in ${outputDir.get().asFile.absoluteFile}") + } } diff --git a/gradle/plugins/build-parameters/build.gradle.kts b/gradle/plugins/build-parameters/build.gradle.kts index 8cdab340d4c3..da78534d2750 100644 --- a/gradle/plugins/build-parameters/build.gradle.kts +++ b/gradle/plugins/build-parameters/build.gradle.kts @@ -114,4 +114,10 @@ buildParameters { description = "Overrides the value of the 'Created-By' jar manifest entry" } } + group("antora") { + bool("downloadNode") { + description = "Whether to download Node.js from the Gradle build" + defaultValue = true + } + } } From b915c80f7957c237a4024c5e30297ce818d5e280 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:02:34 +0100 Subject: [PATCH 09/57] Install Node.js via GitHub Action --- .github/workflows/main.yml | 5 +++++ .github/zizmor.yml | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .github/zizmor.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 076d64c040af..e8dd8512ae8c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -122,10 +122,15 @@ jobs: run: | sudo apt-get update sudo apt-get install graphviz + - name: Install Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + with: + node-version-file: documentation/.tool-versions - name: Build Documentation uses: ./.github/actions/run-gradle with: encryptionKey: ${{ secrets.GRADLE_ENCRYPTION_KEY }} arguments: | antora \ + -Pantora.downloadNode=false \ -Dscan.tag.Documentation diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 000000000000..a646ea1727c0 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,5 @@ +rules: + cache-poisoning: + ignore: + # reports issues for setup-node which isn't used while releasing + - main.yml From 6f770d0efd313133767720159f0fccc8272b311b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:06 +0100 Subject: [PATCH 10/57] Move images to Antora module --- .../extensions_BrokenLifecycleMethodConfigDemo.png | Bin .../extensions_BrokenLifecycleMethodConfigDemo.txt | 0 .../ROOT}/images/extensions_DatabaseTestsDemo.png | Bin .../ROOT}/images/extensions_DatabaseTestsDemo.txt | 0 .../ROOT}/images/extensions_StoreHierarchy.svg | 0 .../ROOT}/images/extensions_lifecycle.png | Bin .../ROOT}/images/extensions_lifecycle_source.docx | Bin .../ROOT}/images/writing-tests_execution_mode.svg | 0 .../ROOT}/images/writing-tests_nested_test_ide.png | Bin gradle/config/checkstyle/suppressions.xml | 2 +- 10 files changed, 1 insertion(+), 1 deletion(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_BrokenLifecycleMethodConfigDemo.png (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_BrokenLifecycleMethodConfigDemo.txt (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_DatabaseTestsDemo.png (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_DatabaseTestsDemo.txt (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_StoreHierarchy.svg (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_lifecycle.png (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/extensions_lifecycle_source.docx (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/writing-tests_execution_mode.svg (100%) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT}/images/writing-tests_nested_test_ide.png (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_BrokenLifecycleMethodConfigDemo.png b/documentation/modules/ROOT/images/extensions_BrokenLifecycleMethodConfigDemo.png similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_BrokenLifecycleMethodConfigDemo.png rename to documentation/modules/ROOT/images/extensions_BrokenLifecycleMethodConfigDemo.png diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_BrokenLifecycleMethodConfigDemo.txt b/documentation/modules/ROOT/images/extensions_BrokenLifecycleMethodConfigDemo.txt similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_BrokenLifecycleMethodConfigDemo.txt rename to documentation/modules/ROOT/images/extensions_BrokenLifecycleMethodConfigDemo.txt diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_DatabaseTestsDemo.png b/documentation/modules/ROOT/images/extensions_DatabaseTestsDemo.png similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_DatabaseTestsDemo.png rename to documentation/modules/ROOT/images/extensions_DatabaseTestsDemo.png diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_DatabaseTestsDemo.txt b/documentation/modules/ROOT/images/extensions_DatabaseTestsDemo.txt similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_DatabaseTestsDemo.txt rename to documentation/modules/ROOT/images/extensions_DatabaseTestsDemo.txt diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_StoreHierarchy.svg b/documentation/modules/ROOT/images/extensions_StoreHierarchy.svg similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_StoreHierarchy.svg rename to documentation/modules/ROOT/images/extensions_StoreHierarchy.svg diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_lifecycle.png b/documentation/modules/ROOT/images/extensions_lifecycle.png similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_lifecycle.png rename to documentation/modules/ROOT/images/extensions_lifecycle.png diff --git a/documentation/src/docs/asciidoc/user-guide/images/extensions_lifecycle_source.docx b/documentation/modules/ROOT/images/extensions_lifecycle_source.docx similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/extensions_lifecycle_source.docx rename to documentation/modules/ROOT/images/extensions_lifecycle_source.docx diff --git a/documentation/src/docs/asciidoc/user-guide/images/writing-tests_execution_mode.svg b/documentation/modules/ROOT/images/writing-tests_execution_mode.svg similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/writing-tests_execution_mode.svg rename to documentation/modules/ROOT/images/writing-tests_execution_mode.svg diff --git a/documentation/src/docs/asciidoc/user-guide/images/writing-tests_nested_test_ide.png b/documentation/modules/ROOT/images/writing-tests_nested_test_ide.png similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/images/writing-tests_nested_test_ide.png rename to documentation/modules/ROOT/images/writing-tests_nested_test_ide.png diff --git a/gradle/config/checkstyle/suppressions.xml b/gradle/config/checkstyle/suppressions.xml index 7572f8b1a4d6..092a2a2dadc9 100644 --- a/gradle/config/checkstyle/suppressions.xml +++ b/gradle/config/checkstyle/suppressions.xml @@ -3,5 +3,5 @@ + files="documentation[\\/]modules[\\/]ROOT[\\/]images[\\/]extensions_StoreHierarchy.svg"/> From 566beecc43fa0eba2a17ad8c1f372a48e4c27b23 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:06 +0100 Subject: [PATCH 11/57] Migrate link attributes to antora.yml --- documentation/antora.yml | 271 +++++++++++++++++ .../src/docs/asciidoc/link-attributes.adoc | 272 ------------------ 2 files changed, 271 insertions(+), 272 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/link-attributes.adoc diff --git a/documentation/antora.yml b/documentation/antora.yml index 5abd0da10059..9afb0753ee7f 100644 --- a/documentation/antora.yml +++ b/documentation/antora.yml @@ -22,3 +22,274 @@ ext: - dir: ./build/plantuml clean: true into: modules/ROOT/images +asciidoc: + attributes: + javadoc-root: "xref:attachment$api/" + # Snapshot Repository + snapshot-repo: 'https://central.sonatype.com/service/rest/repository/browse/maven-snapshots' + # Base Links + junit-team: 'https://github.com/junit-team' + junit-framework-repo: '{junit-team}/junit-framework' + current-branch: '{junit-framework-repo}/tree/{release-branch}' + # Platform Commons + junit-platform-support-package: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/package-summary.html[org.junit.platform.commons.support]' + AnnotationSupport: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/AnnotationSupport.html[AnnotationSupport]' + ClassSupport: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ClassSupport.html[ClassSupport]' + ConversionSupport: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/conversion/ConversionSupport.html[ConversionSupport]' + ModifierSupport: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ModifierSupport.html[ModifierSupport]' + ReflectionSupport: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ReflectionSupport.html[ReflectionSupport]' + Testable: '{javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/annotation/Testable.html[@Testable]' + # Platform Console Launcher + junit-platform-console: '{javadoc-root}/org.junit.platform.console/org/junit/platform/console/package-summary.html[junit-platform-console]' + ConsoleLauncher: '{javadoc-root}/org.junit.platform.console/org/junit/platform/console/ConsoleLauncher.html[ConsoleLauncher]' + # Platform Engine + junit-platform-engine: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/package-summary.html[junit-platform-engine]' + junit-platform-engine-support-discovery: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/discovery/package-summary.html[org.junit.platform.engine.support.discovery]' + CancellationToken: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/CancellationToken.html[CancellationToken]' + ClasspathResourceSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClasspathResourceSelector.html[ClasspathResourceSelector]' + ClasspathRootSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClasspathRootSelector.html[ClasspathRootSelector]' + ClassSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClassSelector.html[ClassSelector]' + DiscoveryIssue: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/DiscoveryIssue.html[DiscoveryIssue]' + DiscoveryIssueReporter: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.html[DiscoveryIssueReporter]' + DirectorySelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DirectorySelector.html[DirectorySelector]' + DiscoverySelectors: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html[DiscoverySelectors]' + DiscoverySelectors_selectClasspathResource: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClasspathResource(java.lang.String)[selectClasspathResource]' + DiscoverySelectors_selectClasspathRoots: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClasspathRoots(java.util.Set)[selectClasspathRoots]' + DiscoverySelectors_selectClass: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClass(java.lang.String)[selectClass]' + DiscoverySelectors_selectDirectory: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectDirectory(java.lang.String)[selectDirectory]' + DiscoverySelectors_selectFile: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectFile(java.lang.String)[selectFile]' + DiscoverySelectors_selectIteration: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectIteration(org.junit.platform.engine.DiscoverySelector,int\...)[selectIteration]' + DiscoverySelectors_selectMethod: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectMethod(java.lang.String)[selectMethod]' + DiscoverySelectors_selectModule: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectModule(java.lang.String)[selectModule]' + DiscoverySelectors_selectNestedClass: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectNestedClass(java.util.List,java.lang.Class)[selectNestedClass]' + DiscoverySelectors_selectNestedMethod: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectNestedMethod(java.util.List,java.lang.Class,java.lang.String)[selectNestedMethod]' + DiscoverySelectors_selectPackage: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectPackage(java.lang.String)[selectPackage]' + DiscoverySelectors_selectUniqueId: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectUniqueId(java.lang.String)[selectUniqueId]' + DiscoverySelectors_selectUri: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectUri(java.lang.String)[selectUri]' + EngineDiscoveryListener: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/EngineDiscoveryListener.html[EngineDiscoveryListener]' + EngineDiscoveryRequest: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/EngineDiscoveryRequest.html[EngineDiscoveryRequest]' + FileSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/FileSelector.html[FileSelector]' + HierarchicalTestEngine: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.html[HierarchicalTestEngine]' + IterationSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/IterationSelector.html[IterationSelector]' + MethodSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/MethodSelector.html[MethodSelector]' + ModuleSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ModuleSelector.html[ModuleSelector]' + NamespacedHierarchicalStore: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.html[NamespacedHierarchicalStore]' + NestedClassSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/NestedClassSelector.html[NestedClassSelector]' + NestedMethodSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/NestedMethodSelector.html[NestedMethodSelector]' + OutputDirectoryCreator: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/OutputDirectoryCreator.html[OutputDirectoryCreator]' + PackageSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/PackageSelector.html[PackageSelector]' + ParallelExecutionConfigurationStrategy: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.html[ParallelExecutionConfigurationStrategy]' + UniqueIdSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/UniqueIdSelector.html[UniqueIdSelector]' + UriSelector: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/UriSelector.html[UriSelector]' + TestEngine: '{javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/TestEngine.html[TestEngine]' + # Platform Launcher API + junit-platform-launcher: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/package-summary.html[junit-platform-launcher]' + DiscoveryIssueException: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/DiscoveryIssueException.html[DiscoveryIssueException]' + Launcher: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/Launcher.html[Launcher]' + LauncherConfig: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherConfig.html[LauncherConfig]' + LauncherDiscoveryListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherDiscoveryListener.html[LauncherDiscoveryListener]' + LauncherDiscoveryRequest: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherDiscoveryRequest.html[LauncherDiscoveryRequest]' + LauncherDiscoveryRequestBuilder: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.html[LauncherDiscoveryRequestBuilder]' + LauncherExecutionRequest: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherExecutionRequest.html[LauncherExecutionRequest]' + LauncherExecutionRequestBuilder: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherExecutionRequestBuilder.html[LauncherExecutionRequestBuilder]' + LauncherFactory: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherFactory.html[LauncherFactory]' + LauncherInterceptor: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherInterceptor.html[LauncherInterceptor]' + LauncherSession: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherSession.html[LauncherSession]' + LauncherSessionListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherSessionListener.html[LauncherSessionListener]' + LoggingListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/LoggingListener.html[LoggingListener]' + PostDiscoveryFilter: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/PostDiscoveryFilter.html[PostDiscoveryFilter]' + SummaryGeneratingListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/SummaryGeneratingListener.html[SummaryGeneratingListener]' + TestExecutionListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/TestExecutionListener.html[TestExecutionListener]' + TestPlan: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/TestPlan.html[TestPlan]' + UniqueIdTrackingListener: '{javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.html[UniqueIdTrackingListener]' + # Platform Reporting + LegacyXmlReportGeneratingListener: '{javadoc-root}/org.junit.platform.reporting/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.html[LegacyXmlReportGeneratingListener]' + OpenTestReportGeneratingListener: '{javadoc-root}/org.junit.platform.reporting/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.html[OpenTestReportGeneratingListener]' + # Platform Suite + suite-api-package: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/package-summary.html[org.junit.platform.suite.api]' + junit-platform-suite-engine: '{javadoc-root}/org.junit.platform.suite.engine/org/junit/platform/suite/engine/package-summary.html[junit-platform-suite-engine]' + Select: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/Select.html[@Select]' + SelectClasspathResource: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectClasspathResource.html[@SelectClasspathResource]' + SelectClasses: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectClasses.html[@SelectClasses]' + SelectDirectories: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectDirectories.html[@SelectDirectories]' + SelectFile: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectFile.html[@SelectFile]' + SelectMethod: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectMethod.html[@SelectMethod]' + SelectModules: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectModules.html[@SelectModules]' + SelectPackages: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectPackages.html[@SelectPackages]' + SelectUris: '{javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectUris.html[@SelectUris]' + # Platform Test Kit + testkit-engine-package: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/package-summary.html[org.junit.platform.testkit.engine]' + EngineExecutionResults: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EngineExecutionResults.html[EngineExecutionResults]' + EngineTestKit: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EngineTestKit.html[EngineTestKit]' + Event: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Event.html[Event]' + EventConditions: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventConditions.html[EventConditions]' + Events: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Events.html[Events]' + EventStatistics: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventStatistics.html[EventStatistics]' + EventType: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventType.html[EventType]' + Executions: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Executions.html[Executions]' + TerminationInfo: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/TerminationInfo.html[TerminationInfo]' + TestExecutionResultConditions: '{javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/TestExecutionResultConditions.html[TestExecutionResultConditions]' + # Jupiter Core API + api-package: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/package-summary.html[org.junit.jupiter.api]' + Assertions: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html[org.junit.jupiter.api.Assertions]' + Assumptions: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Assumptions.html[org.junit.jupiter.api.Assumptions]' + AutoClose: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/AutoClose.html[@AutoClose]' + ClassOrderer_ClassName: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.ClassName.html[ClassOrderer.ClassName]' + ClassOrderer_Default: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.Default.html[ClassOrderer.Default]' + ClassOrderer_DisplayName: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.DisplayName.html[ClassOrderer.DisplayName]' + ClassOrderer_OrderAnnotation: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.OrderAnnotation.html[ClassOrderer.OrderAnnotation]' + ClassOrderer_Random: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.Random.html[ClassOrderer.Random]' + ClassOrderer: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.html[ClassOrderer]' + ClassTemplate: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassTemplate.html[@ClassTemplate]' + Disabled: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Disabled.html[@Disabled]' + MethodOrderer_Default: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.Default.html[MethodOrderer.Default]' + MethodOrderer_DisplayName: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.DisplayName.html[MethodOrderer.DisplayName]' + MethodOrderer_MethodName: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.MethodName.html[MethodOrderer.MethodName]' + MethodOrderer_OrderAnnotation: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.OrderAnnotation.html[MethodOrderer.OrderAnnotation]' + MethodOrderer_Random: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.Random.html[MethodOrderer.Random]' + MethodOrderer: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.html[MethodOrderer]' + Named: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Named.html[Named]' + Order: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Order.html[@Order]' + RepetitionInfo: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/RepetitionInfo.html[RepetitionInfo]' + TestInfo: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestInfo.html[TestInfo]' + TestClassOrder: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestClassOrder.html[@TestClassOrder]' + TestMethodOrder: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestMethodOrder.html[@TestMethodOrder]' + TestReporter: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestReporter.html[TestReporter]' + TestTemplate: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestTemplate.html[@TestTemplate]' + # @DefaultLocale and @DefaultTimeZone + DefaultLocale: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/DefaultLocale.html[@DefaultLocale]' + DefaultTimeZone: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/DefaultTimeZone.html[@DefaultTimeZone]' + LocaleProvider: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/LocaleProvider.html[LocaleProvider]' + TimeZoneProvider: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/TimeZoneProvider.html[TimeZoneProvider]' + ReadsDefaultLocale: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/ReadsDefaultLocale.html[@ReadsDefaultLocale]' + ReadsDefaultTimeZone: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/ReadsDefaultTimeZone.html[@ReadsDefaultTimeZone]' + WritesDefaultLocale: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/WritesDefaultLocale.html[@WritesDefaultLocale]' + WritesDefaultTimeZone: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/WritesDefaultTimeZone.html[@WritesDefaultTimeZone]' + # Jupiter Parallel API + Execution: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Execution.html[@Execution]' + Isolated: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Isolated.html[@Isolated]' + ResourceLock: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLock.html[@ResourceLock]' + ResourceLockTarget: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLockTarget.html[ResourceLockTarget]' + ResourceLocksProvider: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLocksProvider.html[ResourceLocksProvider]' + Resources: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Resources.html[Resources]' + # Jupiter Extension APIs + extension-api-package: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/package-summary.html[org.junit.jupiter.api.extension]' + AfterAllCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterAllCallback.html[AfterAllCallback]' + AfterClassTemplateInvocationCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.html[AfterClassTemplateInvocationCallback]' + AfterEachCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterEachCallback.html[AfterEachCallback]' + AfterTestExecutionCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterTestExecutionCallback.html[AfterTestExecutionCallback]' + ParameterContext: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterContext.html[ParameterContext]' + BeforeAllCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeAllCallback.html[BeforeAllCallback]' + BeforeClassTemplateInvocationCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.html[BeforeClassTemplateInvocationCallback]' + BeforeEachCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeEachCallback.html[BeforeEachCallback]' + BeforeTestExecutionCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.html[BeforeTestExecutionCallback]' + ClassTemplateInvocationContext: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.html[ClassTemplateInvocationContext]' + ClassTemplateInvocationContextProvider: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.html[ClassTemplateInvocationContextProvider]' + ExecutableInvoker: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutableInvoker.html[ExecutableInvoker]' + ExecutionCondition: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutionCondition.html[ExecutionCondition]' + ExtendWith: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtendWith.html[@ExtendWith]' + ExtensionContext: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.html[ExtensionContext]' + ExtensionContext_Store: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.Store.html[Store]' + ExtensionContext_StoreScope: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.StoreScope.html[StoreScope]' + InvocationInterceptor: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/InvocationInterceptor.html[InvocationInterceptor]' + LifecycleMethodExecutionExceptionHandler: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.html[LifecycleMethodExecutionExceptionHandler]' + ParameterResolver: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterResolver.html[ParameterResolver]' + RegisterExtension: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/RegisterExtension.html[@RegisterExtension]' + TestExecutionExceptionHandler: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.html[TestExecutionExceptionHandler]' + TestInstanceFactory: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstanceFactory.html[TestInstanceFactory]' + TestInstancePostProcessor: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html[TestInstancePostProcessor]' + TestInstancePreConstructCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.html[TestInstancePreConstructCallback]' + TestInstancePreDestroyCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.html[TestInstancePreDestroyCallback]' + TestTemplateInvocationContext: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContext.html[TestTemplateInvocationContext]' + TestTemplateInvocationContextProvider: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.html[TestTemplateInvocationContextProvider]' + TestWatcher: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestWatcher.html[TestWatcher]' + PreInterruptCallback: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/PreInterruptCallback.html[PreInterruptCallback]' + # Jupiter Conditions + DisabledForJreRange: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledForJreRange.html[@DisabledForJreRange]' + DisabledIf: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIf.html[@DisabledIf]' + DisabledIfEnvironmentVariable: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.html[@DisabledIfEnvironmentVariable]' + DisabledIfSystemProperty: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIfSystemProperty.html[@DisabledIfSystemProperty]' + DisabledInNativeImage: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledInNativeImage.html[@DisabledInNativeImage]' + DisabledOnJre: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledOnJre.html[@DisabledOnJre]' + DisabledOnOs: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledOnOs.html[@DisabledOnOs]' + EnabledForJreRange: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledForJreRange.html[@EnabledForJreRange]' + EnabledIf: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIf.html[@EnabledIf]' + EnabledIfEnvironmentVariable: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.html[@EnabledIfEnvironmentVariable]' + EnabledIfSystemProperty: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIfSystemProperty.html[@EnabledIfSystemProperty]' + EnabledInNativeImage: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html[@EnabledInNativeImage]' + EnabledOnJre: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledOnJre.html[@EnabledOnJre]' + EnabledOnOs: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledOnOs.html[@EnabledOnOs]' + JRE: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/JRE.html[JRE]' + # Jupiter I/O + TempDir: '{javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/io/TempDir.html[@TempDir]' + # Jupiter Params + params-provider-package: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/package-summary.html[org.junit.jupiter.params.provider]' + AfterParameterizedClassInvocation: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/AfterParameterizedClassInvocation.html[@AfterParameterizedClassInvocation]' + AnnotationBasedArgumentConverter: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.html[AnnotationBasedArgumentConverter]' + AnnotationBasedArgumentsProvider: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.html[AnnotationBasedArgumentsProvider]' + AggregateWith: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/AggregateWith.html[@AggregateWith]' + Arguments: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/Arguments.html[Arguments]' + ArgumentsProvider: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/ArgumentsProvider.html[ArgumentsProvider]' + ArgumentsAccessor: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/ArgumentsAccessor.html[ArgumentsAccessor]' + ArgumentsAggregator: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/ArgumentsAggregator.html[ArgumentsAggregator]' + BeforeParameterizedClassInvocation: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/BeforeParameterizedClassInvocation.html[@BeforeParameterizedClassInvocation]' + CsvArgumentsProvider: '{junit-framework-repo}/blob/main/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java[CsvArgumentsProvider]' + EmptySource: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/EmptySource.html[@EmptySource]' + FieldSource: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/FieldSource.html[@FieldSource]' + MethodSource: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/MethodSource.html[@MethodSource]' + NullAndEmptySource: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/NullAndEmptySource.html[@NullAndEmptySource]' + NullSource: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/NullSource.html[@NullSource]' + Parameter: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/Parameter.html[@Parameter]' + ParameterizedClass: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedClass.html[@ParameterizedClass]' + ParameterizedTest: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html[@ParameterizedTest]' + ParameterInfo: '{javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/support/ParameterInfo.html[ParameterInfo]' + ValueArgumentsProvider: '{junit-framework-repo}/blob/main/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java[ValueArgumentsProvider]' + # Jupiter Engine + junit-jupiter-engine: '{javadoc-root}/org.junit.jupiter.engine/org/junit/jupiter/engine/package-summary.html[junit-jupiter-engine]' + # Jupiter Extension Implementations + AutoCloseExtension: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java[AutoCloseExtension]' + DisabledCondition: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java[DisabledCondition]' + RepetitionExtension: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java[RepetitionExtension]' + TempDirectory: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java[TempDirectory]' + TestInfoParameterResolver: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java[TestInfoParameterResolver]' + TestReporterParameterResolver: '{current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java[TestReporterParameterResolver]' + TypeBasedParameterResolver: '{current-branch}/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java[TypeBasedParameterResolver]' + # Jupiter Examples + CustomAnnotationParameterResolver: '{current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java[CustomAnnotationParameterResolver]' + CustomTypeParameterResolver: '{current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java[CustomTypeParameterResolver]' + MapOfListsTypeBasedParameterResolver: '{current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java[MapOfListsTypeBasedParameterResolver]' + # Jupiter Migration Support + EnableJUnit4MigrationSupport: '{javadoc-root}/org.junit.jupiter.migrationsupport/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.html[@EnableJUnit4MigrationSupport]' + EnableRuleMigrationSupport: '{javadoc-root}/org.junit.jupiter.migrationsupport/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.html[@EnableRuleMigrationSupport]' + # JUnit Start + JUnit: '{javadoc-root}/org.junit.start/org/junit/start/JUnit.html[JUnit]' + # Vintage + junit-vintage-engine: '{javadoc-root}/org.junit.vintage.engine/org/junit/vintage/engine/package-summary.html[junit-vintage-engine]' + # Examples Repository + junit-examples-repo: '{junit-team}/junit-examples' + junit-jupiter-starter-ant: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-ant[junit-jupiter-starter-ant]' + junit-jupiter-starter-gradle-groovy: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle-groovy[junit-jupiter-starter-gradle-groovy]' + junit-jupiter-starter-gradle-kotlin: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle-kotlin[junit-jupiter-starter-gradle-kotlin]' + junit-jupiter-starter-gradle: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle[junit-jupiter-starter-gradle]' + junit-jupiter-starter-maven: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-maven[junit-jupiter-starter-maven]' + RandomParametersExtension: '{junit-examples-repo}/tree/{release-branch}/junit-jupiter-extensions/src/main/java/com/example/random/RandomParametersExtension.java[RandomParametersExtension]' + # Third-party Links + API: 'https://apiguardian-team.github.io/apiguardian/docs/current/api/[@API]' + API_Guardian: 'https://github.com/apiguardian-team/apiguardian[@API Guardian]' + AssertJ: 'https://assertj.github.io/doc/[AssertJ]' + Checkstyle: 'https://checkstyle.sourceforge.io[Checkstyle]' + DiscussionsQA: 'https://github.com/junit-team/junit-framework/discussions/categories/q-a[Q&A category on GitHub Discussions]' + Hamcrest: 'https://hamcrest.org/JavaHamcrest/[Hamcrest]' + Jimfs: 'https://google.github.io/jimfs/[Jimfs]' + Log4j: 'https://logging.apache.org/log4j/2.x/[Log4j]' + Log4j_JDK_Logging_Adapter: 'https://logging.apache.org/log4j/2.x/log4j-jul/index.html[Log4j JDK Logging Adapter]' + Logback: 'https://logback.qos.ch/[Logback]' + LogManager: 'https://docs.oracle.com/en/java/javase/17/docs/api/java.logging/java/util/logging/LogManager.html[LogManager]' + Maven_Central: 'https://central.sonatype.com/[Maven Central]' + MockitoExtension: 'https://github.com/mockito/mockito/blob/release/2.x/subprojects/junit-jupiter/src/main/java/org/mockito/junit/jupiter/MockitoExtension.java[MockitoExtension]' + ServiceLoader: '{jdk-javadoc-base-url}/java.base/java/util/ServiceLoader.html[ServiceLoader]' + SpringExtension: 'https://github.com/spring-projects/spring-framework/tree/HEAD/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java[SpringExtension]' + StackOverflow: 'https://stackoverflow.com/questions/tagged/junit5[Stack Overflow]' + Truth: 'https://truth.dev/[Truth]' + OpenTestReporting: 'https://github.com/ota4j-team/open-test-reporting[Open Test Reporting]' + OpenTestReportingCliTool: 'https://github.com/ota4j-team/open-test-reporting#cli-tool-for-validation-and-format-conversion[Open Test Reporting CLI Tool]' diff --git a/documentation/src/docs/asciidoc/link-attributes.adoc b/documentation/src/docs/asciidoc/link-attributes.adoc deleted file mode 100644 index 649b7d2e847d..000000000000 --- a/documentation/src/docs/asciidoc/link-attributes.adoc +++ /dev/null @@ -1,272 +0,0 @@ -:javadoc-root: link:../api -ifdef::backend-pdf[] -:javadoc-root: https://docs.junit.org/{docs-version}/api -endif::[] -// Snapshot Repository -:snapshot-repo: https://central.sonatype.com/service/rest/repository/browse/maven-snapshots -// Base Links -:junit-team: https://github.com/junit-team -:junit-framework-repo: {junit-team}/junit-framework -:current-branch: {junit-framework-repo}/tree/{release-branch} -// Platform Commons -:junit-platform-support-package: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/package-summary.html[org.junit.platform.commons.support] -:AnnotationSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/AnnotationSupport.html[AnnotationSupport] -:ClassSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ClassSupport.html[ClassSupport] -:ConversionSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/conversion/ConversionSupport.html[ConversionSupport] -:ModifierSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ModifierSupport.html[ModifierSupport] -:ReflectionSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ReflectionSupport.html[ReflectionSupport] -:Testable: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/annotation/Testable.html[@Testable] -// Platform Console Launcher -:junit-platform-console: {javadoc-root}/org.junit.platform.console/org/junit/platform/console/package-summary.html[junit-platform-console] -:ConsoleLauncher: {javadoc-root}/org.junit.platform.console/org/junit/platform/console/ConsoleLauncher.html[ConsoleLauncher] -// Platform Engine -:junit-platform-engine: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/package-summary.html[junit-platform-engine] -:junit-platform-engine-support-discovery: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/discovery/package-summary.html[org.junit.platform.engine.support.discovery] -:CancellationToken: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/CancellationToken.html[CancellationToken] -:ClasspathResourceSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClasspathResourceSelector.html[ClasspathResourceSelector] -:ClasspathRootSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClasspathRootSelector.html[ClasspathRootSelector] -:ClassSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ClassSelector.html[ClassSelector] -:DiscoveryIssue: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/DiscoveryIssue.html[DiscoveryIssue] -:DiscoveryIssueReporter: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/discovery/DiscoveryIssueReporter.html[DiscoveryIssueReporter] -:DirectorySelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DirectorySelector.html[DirectorySelector] -:DiscoverySelectors: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html[DiscoverySelectors] -:DiscoverySelectors_selectClasspathResource: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClasspathResource(java.lang.String)[selectClasspathResource] -:DiscoverySelectors_selectClasspathRoots: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClasspathRoots(java.util.Set)[selectClasspathRoots] -:DiscoverySelectors_selectClass: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectClass(java.lang.String)[selectClass] -:DiscoverySelectors_selectDirectory: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectDirectory(java.lang.String)[selectDirectory] -:DiscoverySelectors_selectFile: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectFile(java.lang.String)[selectFile] -:DiscoverySelectors_selectIteration: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectIteration(org.junit.platform.engine.DiscoverySelector,int\...)[selectIteration] -:DiscoverySelectors_selectMethod: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectMethod(java.lang.String)[selectMethod] -:DiscoverySelectors_selectModule: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectModule(java.lang.String)[selectModule] -:DiscoverySelectors_selectNestedClass: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectNestedClass(java.util.List,java.lang.Class)[selectNestedClass] -:DiscoverySelectors_selectNestedMethod: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectNestedMethod(java.util.List,java.lang.Class,java.lang.String)[selectNestedMethod] -:DiscoverySelectors_selectPackage: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectPackage(java.lang.String)[selectPackage] -:DiscoverySelectors_selectUniqueId: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectUniqueId(java.lang.String)[selectUniqueId] -:DiscoverySelectors_selectUri: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/DiscoverySelectors.html#selectUri(java.lang.String)[selectUri] -:EngineDiscoveryListener: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/EngineDiscoveryListener.html[EngineDiscoveryListener] -:EngineDiscoveryRequest: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/EngineDiscoveryRequest.html[EngineDiscoveryRequest] -:FileSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/FileSelector.html[FileSelector] -:HierarchicalTestEngine: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/hierarchical/HierarchicalTestEngine.html[HierarchicalTestEngine] -:IterationSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/IterationSelector.html[IterationSelector] -:MethodSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/MethodSelector.html[MethodSelector] -:ModuleSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/ModuleSelector.html[ModuleSelector] -:NamespacedHierarchicalStore: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.html[NamespacedHierarchicalStore] -:NestedClassSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/NestedClassSelector.html[NestedClassSelector] -:NestedMethodSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/NestedMethodSelector.html[NestedMethodSelector] -:OutputDirectoryCreator: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/OutputDirectoryCreator.html[OutputDirectoryCreator] -:PackageSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/PackageSelector.html[PackageSelector] -:ParallelExecutionConfigurationStrategy: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/support/hierarchical/ParallelExecutionConfigurationStrategy.html[ParallelExecutionConfigurationStrategy] -:UniqueIdSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/UniqueIdSelector.html[UniqueIdSelector] -:UriSelector: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/discovery/UriSelector.html[UriSelector] -:TestEngine: {javadoc-root}/org.junit.platform.engine/org/junit/platform/engine/TestEngine.html[TestEngine] -// Platform Launcher API -:junit-platform-launcher: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/package-summary.html[junit-platform-launcher] -:DiscoveryIssueException: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/DiscoveryIssueException.html[DiscoveryIssueException] -:Launcher: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/Launcher.html[Launcher] -:LauncherConfig: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherConfig.html[LauncherConfig] -:LauncherDiscoveryListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherDiscoveryListener.html[LauncherDiscoveryListener] -:LauncherDiscoveryRequest: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherDiscoveryRequest.html[LauncherDiscoveryRequest] -:LauncherDiscoveryRequestBuilder: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.html[LauncherDiscoveryRequestBuilder] -:LauncherExecutionRequest: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherExecutionRequest.html[LauncherExecutionRequest] -:LauncherExecutionRequestBuilder: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherExecutionRequestBuilder.html[LauncherExecutionRequestBuilder] -:LauncherFactory: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/core/LauncherFactory.html[LauncherFactory] -:LauncherInterceptor: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherInterceptor.html[LauncherInterceptor] -:LauncherSession: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherSession.html[LauncherSession] -:LauncherSessionListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/LauncherSessionListener.html[LauncherSessionListener] -:LoggingListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/LoggingListener.html[LoggingListener] -:PostDiscoveryFilter: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/PostDiscoveryFilter.html[PostDiscoveryFilter] -:SummaryGeneratingListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/SummaryGeneratingListener.html[SummaryGeneratingListener] -:TestExecutionListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/TestExecutionListener.html[TestExecutionListener] -:TestPlan: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/TestPlan.html[TestPlan] -:UniqueIdTrackingListener: {javadoc-root}/org.junit.platform.launcher/org/junit/platform/launcher/listeners/UniqueIdTrackingListener.html[UniqueIdTrackingListener] -// Platform Reporting -:LegacyXmlReportGeneratingListener: {javadoc-root}/org.junit.platform.reporting/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListener.html[LegacyXmlReportGeneratingListener] -:OpenTestReportGeneratingListener: {javadoc-root}/org.junit.platform.reporting/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.html[OpenTestReportGeneratingListener] -// Platform Suite -:suite-api-package: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/package-summary.html[org.junit.platform.suite.api] -:junit-platform-suite-engine: {javadoc-root}/org.junit.platform.suite.engine/org/junit/platform/suite/engine/package-summary.html[junit-platform-suite-engine] -:Select: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/Select.html[@Select] -:SelectClasspathResource: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectClasspathResource.html[@SelectClasspathResource] -:SelectClasses: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectClasses.html[@SelectClasses] -:SelectDirectories: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectDirectories.html[@SelectDirectories] -:SelectFile: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectFile.html[@SelectFile] -:SelectMethod: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectMethod.html[@SelectMethod] -:SelectModules: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectModules.html[@SelectModules] -:SelectPackages: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectPackages.html[@SelectPackages] -:SelectUris: {javadoc-root}/org.junit.platform.suite.api/org/junit/platform/suite/api/SelectUris.html[@SelectUris] -// Platform Test Kit -:testkit-engine-package: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/package-summary.html[org.junit.platform.testkit.engine] -:EngineExecutionResults: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EngineExecutionResults.html[EngineExecutionResults] -:EngineTestKit: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EngineTestKit.html[EngineTestKit] -:Event: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Event.html[Event] -:EventConditions: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventConditions.html[EventConditions] -:Events: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Events.html[Events] -:EventStatistics: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventStatistics.html[EventStatistics] -:EventType: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/EventType.html[EventType] -:Executions: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/Executions.html[Executions] -:TerminationInfo: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/TerminationInfo.html[TerminationInfo] -:TestExecutionResultConditions: {javadoc-root}/org.junit.platform.testkit/org/junit/platform/testkit/engine/TestExecutionResultConditions.html[TestExecutionResultConditions] -// Jupiter Core API -:api-package: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/package-summary.html[org.junit.jupiter.api] -:Assertions: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html[org.junit.jupiter.api.Assertions] -:Assumptions: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Assumptions.html[org.junit.jupiter.api.Assumptions] -:AutoClose: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/AutoClose.html[@AutoClose] -:ClassOrderer_ClassName: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.ClassName.html[ClassOrderer.ClassName] -:ClassOrderer_Default: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.Default.html[ClassOrderer.Default] -:ClassOrderer_DisplayName: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.DisplayName.html[ClassOrderer.DisplayName] -:ClassOrderer_OrderAnnotation: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.OrderAnnotation.html[ClassOrderer.OrderAnnotation] -:ClassOrderer_Random: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.Random.html[ClassOrderer.Random] -:ClassOrderer: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassOrderer.html[ClassOrderer] -:ClassTemplate: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/ClassTemplate.html[@ClassTemplate] -:Disabled: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Disabled.html[@Disabled] -:MethodOrderer_Default: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.Default.html[MethodOrderer.Default] -:MethodOrderer_DisplayName: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.DisplayName.html[MethodOrderer.DisplayName] -:MethodOrderer_MethodName: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.MethodName.html[MethodOrderer.MethodName] -:MethodOrderer_OrderAnnotation: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.OrderAnnotation.html[MethodOrderer.OrderAnnotation] -:MethodOrderer_Random: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.Random.html[MethodOrderer.Random] -:MethodOrderer: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/MethodOrderer.html[MethodOrderer] -:Named: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Named.html[Named] -:Order: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/Order.html[@Order] -:RepetitionInfo: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/RepetitionInfo.html[RepetitionInfo] -:TestInfo: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestInfo.html[TestInfo] -:TestClassOrder: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestClassOrder.html[@TestClassOrder] -:TestMethodOrder: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestMethodOrder.html[@TestMethodOrder] -:TestReporter: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestReporter.html[TestReporter] -:TestTemplate: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/TestTemplate.html[@TestTemplate] -// @DefaultLocale and @DefaultTimeZone -:DefaultLocale: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/DefaultLocale.html[@DefaultLocale] -:DefaultTimeZone: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/DefaultTimeZone.html[@DefaultTimeZone] -:LocaleProvider: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/LocaleProvider.html[LocaleProvider] -:TimeZoneProvider: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/TimeZoneProvider.html[TimeZoneProvider] -:ReadsDefaultLocale: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/ReadsDefaultLocale.html[@ReadsDefaultLocale] -:ReadsDefaultTimeZone: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/ReadsDefaultTimeZone.html[@ReadsDefaultTimeZone] -:WritesDefaultLocale: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/WritesDefaultLocale.html[@WritesDefaultLocale] -:WritesDefaultTimeZone: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/util/WritesDefaultTimeZone.html[@WritesDefaultTimeZone] -// Jupiter Parallel API -:Execution: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Execution.html[@Execution] -:Isolated: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Isolated.html[@Isolated] -:ResourceLock: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLock.html[@ResourceLock] -:ResourceLockTarget: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLockTarget.html[ResourceLockTarget] -:ResourceLocksProvider: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/ResourceLocksProvider.html[ResourceLocksProvider] -:Resources: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/parallel/Resources.html[Resources] -// Jupiter Extension APIs -:extension-api-package: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/package-summary.html[org.junit.jupiter.api.extension] -:AfterAllCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterAllCallback.html[AfterAllCallback] -:AfterClassTemplateInvocationCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterClassTemplateInvocationCallback.html[AfterClassTemplateInvocationCallback] -:AfterEachCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterEachCallback.html[AfterEachCallback] -:AfterTestExecutionCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/AfterTestExecutionCallback.html[AfterTestExecutionCallback] -:ParameterContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterContext.html[ParameterContext] -:BeforeAllCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeAllCallback.html[BeforeAllCallback] -:BeforeClassTemplateInvocationCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeClassTemplateInvocationCallback.html[BeforeClassTemplateInvocationCallback] -:BeforeEachCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeEachCallback.html[BeforeEachCallback] -:BeforeTestExecutionCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/BeforeTestExecutionCallback.html[BeforeTestExecutionCallback] -:ClassTemplateInvocationContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ClassTemplateInvocationContext.html[ClassTemplateInvocationContext] -:ClassTemplateInvocationContextProvider: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ClassTemplateInvocationContextProvider.html[ClassTemplateInvocationContextProvider] -:ExecutableInvoker: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutableInvoker.html[ExecutableInvoker] -:ExecutionCondition: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutionCondition.html[ExecutionCondition] -:ExtendWith: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtendWith.html[@ExtendWith] -:ExtensionContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.html[ExtensionContext] -:ExtensionContext_Store: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.Store.html[Store] -:ExtensionContext_StoreScope: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.StoreScope.html[StoreScope] -:InvocationInterceptor: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/InvocationInterceptor.html[InvocationInterceptor] -:LifecycleMethodExecutionExceptionHandler: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/LifecycleMethodExecutionExceptionHandler.html[LifecycleMethodExecutionExceptionHandler] -:ParameterResolver: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterResolver.html[ParameterResolver] -:RegisterExtension: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/RegisterExtension.html[@RegisterExtension] -:TestExecutionExceptionHandler: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestExecutionExceptionHandler.html[TestExecutionExceptionHandler] -:TestInstanceFactory: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstanceFactory.html[TestInstanceFactory] -:TestInstancePostProcessor: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePostProcessor.html[TestInstancePostProcessor] -:TestInstancePreConstructCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePreConstructCallback.html[TestInstancePreConstructCallback] -:TestInstancePreDestroyCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestInstancePreDestroyCallback.html[TestInstancePreDestroyCallback] -:TestTemplateInvocationContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContext.html[TestTemplateInvocationContext] -:TestTemplateInvocationContextProvider: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.html[TestTemplateInvocationContextProvider] -:TestWatcher: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestWatcher.html[TestWatcher] -:PreInterruptCallback: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/PreInterruptCallback.html[PreInterruptCallback] -// Jupiter Conditions -:DisabledForJreRange: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledForJreRange.html[@DisabledForJreRange] -:DisabledIf: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIf.html[@DisabledIf] -:DisabledIfEnvironmentVariable: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.html[@DisabledIfEnvironmentVariable] -:DisabledIfSystemProperty: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledIfSystemProperty.html[@DisabledIfSystemProperty] -:DisabledInNativeImage: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledInNativeImage.html[@DisabledInNativeImage] -:DisabledOnJre: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledOnJre.html[@DisabledOnJre] -:DisabledOnOs: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/DisabledOnOs.html[@DisabledOnOs] -:EnabledForJreRange: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledForJreRange.html[@EnabledForJreRange] -:EnabledIf: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIf.html[@EnabledIf] -:EnabledIfEnvironmentVariable: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.html[@EnabledIfEnvironmentVariable] -:EnabledIfSystemProperty: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledIfSystemProperty.html[@EnabledIfSystemProperty] -:EnabledInNativeImage: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html[@EnabledInNativeImage] -:EnabledOnJre: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledOnJre.html[@EnabledOnJre] -:EnabledOnOs: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledOnOs.html[@EnabledOnOs] -:JRE: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/condition/JRE.html[JRE] -// Jupiter I/O -:TempDir: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/io/TempDir.html[@TempDir] -// Jupiter Params -:params-provider-package: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/package-summary.html[org.junit.jupiter.params.provider] -:AfterParameterizedClassInvocation: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/AfterParameterizedClassInvocation.html[@AfterParameterizedClassInvocation] -:AnnotationBasedArgumentConverter: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/converter/AnnotationBasedArgumentConverter.html[AnnotationBasedArgumentConverter] -:AnnotationBasedArgumentsProvider: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/AnnotationBasedArgumentsProvider.html[AnnotationBasedArgumentsProvider] -:AggregateWith: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/AggregateWith.html[@AggregateWith] -:Arguments: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/Arguments.html[Arguments] -:ArgumentsProvider: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/ArgumentsProvider.html[ArgumentsProvider] -:ArgumentsAccessor: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/ArgumentsAccessor.html[ArgumentsAccessor] -:ArgumentsAggregator: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/aggregator/ArgumentsAggregator.html[ArgumentsAggregator] -:BeforeParameterizedClassInvocation: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/BeforeParameterizedClassInvocation.html[@BeforeParameterizedClassInvocation] -:CsvArgumentsProvider: {junit-framework-repo}/blob/main/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/CsvArgumentsProvider.java[CsvArgumentsProvider] -:EmptySource: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/EmptySource.html[@EmptySource] -:FieldSource: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/FieldSource.html[@FieldSource] -:MethodSource: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/MethodSource.html[@MethodSource] -:NullAndEmptySource: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/NullAndEmptySource.html[@NullAndEmptySource] -:NullSource: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/provider/NullSource.html[@NullSource] -:Parameter: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/Parameter.html[@Parameter] -:ParameterizedClass: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedClass.html[@ParameterizedClass] -:ParameterizedTest: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html[@ParameterizedTest] -:ParameterInfo: {javadoc-root}/org.junit.jupiter.params/org/junit/jupiter/params/support/ParameterInfo.html[ParameterInfo] -:ValueArgumentsProvider: {junit-framework-repo}/blob/main/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ValueArgumentsProvider.java[ValueArgumentsProvider] -// Jupiter Engine -:junit-jupiter-engine: {javadoc-root}/org.junit.jupiter.engine/org/junit/jupiter/engine/package-summary.html[junit-jupiter-engine] -// Jupiter Extension Implementations -:AutoCloseExtension: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/AutoCloseExtension.java[AutoCloseExtension] -:DisabledCondition: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/DisabledCondition.java[DisabledCondition] -:RepetitionExtension: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/RepetitionExtension.java[RepetitionExtension] -:TempDirectory: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java[TempDirectory] -:TestInfoParameterResolver: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestInfoParameterResolver.java[TestInfoParameterResolver] -:TestReporterParameterResolver: {current-branch}/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TestReporterParameterResolver.java[TestReporterParameterResolver] -:TypeBasedParameterResolver: {current-branch}/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolver.java[TypeBasedParameterResolver] -// Jupiter Examples -:CustomAnnotationParameterResolver: {current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomAnnotationParameterResolver.java[CustomAnnotationParameterResolver] -:CustomTypeParameterResolver: {current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/CustomTypeParameterResolver.java[CustomTypeParameterResolver] -:MapOfListsTypeBasedParameterResolver: {current-branch}/jupiter-tests/src/test/java/org/junit/jupiter/engine/execution/injection/sample/MapOfListsTypeBasedParameterResolver.java[MapOfListsTypeBasedParameterResolver] -// Jupiter Migration Support -:EnableJUnit4MigrationSupport: {javadoc-root}/org.junit.jupiter.migrationsupport/org/junit/jupiter/migrationsupport/EnableJUnit4MigrationSupport.html[@EnableJUnit4MigrationSupport] -:EnableRuleMigrationSupport: {javadoc-root}/org.junit.jupiter.migrationsupport/org/junit/jupiter/migrationsupport/rules/EnableRuleMigrationSupport.html[@EnableRuleMigrationSupport] -// JUnit Start -:JUnit: {javadoc-root}/org.junit.start/org/junit/start/JUnit.html[JUnit] -// Vintage -:junit-vintage-engine: {javadoc-root}/org.junit.vintage.engine/org/junit/vintage/engine/package-summary.html[junit-vintage-engine] -// Examples Repository -:junit-examples-repo: {junit-team}/junit-examples -:junit-jupiter-starter-ant: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-ant[junit-jupiter-starter-ant] -:junit-jupiter-starter-gradle-groovy: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle-groovy[junit-jupiter-starter-gradle-groovy] -:junit-jupiter-starter-gradle-kotlin: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle-kotlin[junit-jupiter-starter-gradle-kotlin] -:junit-jupiter-starter-gradle: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-gradle[junit-jupiter-starter-gradle] -:junit-jupiter-starter-maven: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-starter-maven[junit-jupiter-starter-maven] -:RandomParametersExtension: {junit-examples-repo}/tree/{release-branch}/junit-jupiter-extensions/src/main/java/com/example/random/RandomParametersExtension.java[RandomParametersExtension] -// Third-party Links -:API: https://apiguardian-team.github.io/apiguardian/docs/current/api/[@API] -:API_Guardian: https://github.com/apiguardian-team/apiguardian[@API Guardian] -:AssertJ: https://assertj.github.io/doc/[AssertJ] -:Checkstyle: https://checkstyle.sourceforge.io[Checkstyle] -:DiscussionsQA: https://github.com/junit-team/junit-framework/discussions/categories/q-a[Q&A category on GitHub Discussions] -:Hamcrest: https://hamcrest.org/JavaHamcrest/[Hamcrest] -:Jimfs: https://google.github.io/jimfs/[Jimfs] -:Log4j: https://logging.apache.org/log4j/2.x/[Log4j] -:Log4j_JDK_Logging_Adapter: https://logging.apache.org/log4j/2.x/log4j-jul/index.html[Log4j JDK Logging Adapter] -:Logback: https://logback.qos.ch/[Logback] -:LogManager: https://docs.oracle.com/en/java/javase/17/docs/api/java.logging/java/util/logging/LogManager.html[LogManager] -:Maven_Central: https://central.sonatype.com/[Maven Central] -:MockitoExtension: https://github.com/mockito/mockito/blob/release/2.x/subprojects/junit-jupiter/src/main/java/org/mockito/junit/jupiter/MockitoExtension.java[MockitoExtension] -:ServiceLoader: {jdk-javadoc-base-url}/java.base/java/util/ServiceLoader.html[ServiceLoader] -:SpringExtension: https://github.com/spring-projects/spring-framework/tree/HEAD/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java[SpringExtension] -:StackOverflow: https://stackoverflow.com/questions/tagged/junit5[Stack Overflow] -:Truth: https://truth.dev/[Truth] -:OpenTestReporting: https://github.com/ota4j-team/open-test-reporting[Open Test Reporting] -:OpenTestReportingCliTool: https://github.com/ota4j-team/open-test-reporting#cli-tool-for-validation-and-format-conversion[Open Test Reporting CLI Tool] From 06c3ee70ad35472090c5a0fd5109960bb2102e9b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:06 +0100 Subject: [PATCH 12/57] Remove Asciidoctor User Guide main document --- .../src/docs/asciidoc/user-guide/index.adoc | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/user-guide/index.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/index.adoc b/documentation/src/docs/asciidoc/user-guide/index.adoc deleted file mode 100644 index cd35b456e2ee..000000000000 --- a/documentation/src/docs/asciidoc/user-guide/index.adoc +++ /dev/null @@ -1,46 +0,0 @@ -[[user-guide]] -= JUnit User Guide -Stefan Bechtold; Sam Brannen; Johannes Link; Matthias Merdes; Marc Philipp; Juliette de Rancourt; Christian Stein -:basedir: {includedir}/user-guide -:pdf-fontsdir: GEM_FONTS_DIR;{includedir}/resources/fonts -:pdf-theme: {includedir}/resources/themes/junit-pdf-theme.yml -:imagesdir: images -:imagesoutdir: {outdir}/user-guide/images -// -:docinfodir: {includedir}/docinfos -:docinfo2: -// -ifdef::backend-pdf[:imagesdir: {imagesoutdir}] -// -// Blank lines are not permitted in the doc-header: https://asciidoctor.org/docs/user-manual/#doc-header -// -:sectnums: -:toclevels: 4 -:last-update-label!: -:figure-caption!: -// - -include::{includedir}/link-attributes.adoc[] - -include::{basedir}/overview.adoc[] - -include::{basedir}/writing-tests.adoc[] - -include::{basedir}/migration-from-junit4.adoc[] - -include::{basedir}/running-tests.adoc[] - -include::{basedir}/extensions.adoc[] - -include::{basedir}/advanced-topics.adoc[] - -include::{basedir}/api-evolution.adoc[] - -include::{basedir}/contributors.adoc[] - -[[release-notes]] -== Release Notes - -The release notes are available link:{releaseNotesUrl}[here]. - -include::{basedir}/appendix.adoc[] From 502839ecfee6c34edeed1fbdaff7d45f620aa6cc Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:07 +0100 Subject: [PATCH 13/57] Move overview.adoc to Antora module --- .../docs/asciidoc/user-guide => modules/ROOT/pages}/overview.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/overview.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/overview.adoc b/documentation/modules/ROOT/pages/overview.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/overview.adoc rename to documentation/modules/ROOT/pages/overview.adoc From af16b074b0152867036fd15a6f981482661a30ac Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:07 +0100 Subject: [PATCH 14/57] Migrate overview.adoc to Antora syntax --- documentation/modules/ROOT/pages/overview.adoc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/modules/ROOT/pages/overview.adoc b/documentation/modules/ROOT/pages/overview.adoc index d1e19b48962e..a5f27923123c 100644 --- a/documentation/modules/ROOT/pages/overview.adoc +++ b/documentation/modules/ROOT/pages/overview.adoc @@ -1,5 +1,5 @@ -[[overview]] -== Overview += Overview +:page-aliases: user-guide/index.adoc The goal of this document is to provide comprehensive reference documentation for programmers writing tests, extension authors, and engine authors as well as build tool @@ -12,7 +12,7 @@ endif::linkToPdf[] endif::backend-html5[] [[overview-what-is-junit]] -=== What is JUnit? +== What is JUnit? JUnit is composed of several different modules from three different sub-projects. @@ -40,28 +40,28 @@ temporarily while migrating tests to JUnit Jupiter or another testing framework native JUnit Platform support. [[overview-java-versions]] -=== Supported Java Versions +== Supported Java Versions JUnit requires Java 17 (or higher) at runtime. However, you can still test code that has been compiled with previous versions of the JDK. [[overview-getting-help]] -=== Getting Help +== Getting Help Ask JUnit-related questions on {StackOverflow} or use the {DiscussionsQA}. [[overview-getting-started]] -=== Getting Started +== Getting Started [[overview-getting-started-junit-artifacts]] -==== Downloading JUnit Artifacts +=== Downloading JUnit Artifacts To find out what artifacts are available for download and inclusion in your project, refer to <>. To set up dependency management for your build, refer to <> and the <>. [[overview-getting-started-features]] -==== JUnit Features +=== JUnit Features To find out what features are available in JUnit {version} and how to use them, read the corresponding sections of this User Guide, organized by topic. @@ -75,7 +75,7 @@ corresponding sections of this User Guide, organized by topic. - <> [[overview-getting-started-example-projects]] -==== Example Projects +=== Example Projects To see complete, working examples of projects that you can copy and experiment with, the {junit-examples-repo}[`junit-examples`] repository is a good place to start. The From c5c89a1102d1ce6578bb59bd3c42b539f6e52991 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:07 +0100 Subject: [PATCH 15/57] Add overview.adoc to navigation --- documentation/modules/ROOT/nav.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index e69de29bb2d1..1daff8e619ee 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -0,0 +1 @@ +* xref:overview.adoc[] From fab5ec028089f474b21e4b0d041bb872d1d03b0a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:08 +0100 Subject: [PATCH 16/57] Move writing-tests.adoc to Antora module --- .../pages/writing-tests/annotations.adoc} | 0 .../ROOT/pages/writing-tests/assertions.adoc | 3940 +++++++++++++++++ .../ROOT/pages/writing-tests/assumptions.adoc | 3940 +++++++++++++++++ .../writing-tests/built-in-extensions.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/class-templates.adoc | 3940 +++++++++++++++++ .../conditional-test-execution.adoc | 3940 +++++++++++++++++ .../ROOT/pages/writing-tests/definitions.adoc | 3940 +++++++++++++++++ ...njection-for-constructors-and-methods.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/disabling-tests.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/display-names.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/dynamic-tests.adoc | 3940 +++++++++++++++++ .../writing-tests/exception-handling.adoc | 3940 +++++++++++++++++ .../ROOT/pages/writing-tests/intro.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/nested-tests.adoc | 3940 +++++++++++++++++ .../writing-tests/parallel-execution.adoc | 3940 +++++++++++++++++ .../parameterized-classes-and-tests.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/repeated-tests.adoc | 3940 +++++++++++++++++ .../writing-tests/tagging-and-filtering.adoc | 3940 +++++++++++++++++ .../test-classes-and-methods.adoc | 3940 +++++++++++++++++ .../writing-tests/test-execution-order.adoc | 3940 +++++++++++++++++ .../test-instance-lifecycle.adoc | 3940 +++++++++++++++++ .../test-interfaces-and-default-methods.adoc | 3940 +++++++++++++++++ .../pages/writing-tests/test-templates.adoc | 3940 +++++++++++++++++ .../ROOT/pages/writing-tests/timeouts.adoc | 3940 +++++++++++++++++ 24 files changed, 90620 insertions(+) rename documentation/{src/docs/asciidoc/user-guide/writing-tests.adoc => modules/ROOT/pages/writing-tests/annotations.adoc} (100%) create mode 100644 documentation/modules/ROOT/pages/writing-tests/assertions.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/assumptions.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/class-templates.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/definitions.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/display-names.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/intro.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/test-templates.adoc create mode 100644 documentation/modules/ROOT/pages/writing-tests/timeouts.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/writing-tests.adoc rename to documentation/modules/ROOT/pages/writing-tests/annotations.adoc diff --git a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/intro.adoc b/documentation/modules/ROOT/pages/writing-tests/intro.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/intro.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc new file mode 100644 index 000000000000..18eddfd55b43 --- /dev/null +++ b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc @@ -0,0 +1,3940 @@ +:testDir: ../../../../src/test/java +:testResourcesDir: ../../../../src/test/resources +:kotlinTestDir: ../../../../src/test/kotlin + +[[writing-tests]] +== Writing Tests + +The following example provides a glimpse at the minimum requirements for writing a test in +JUnit Jupiter. Subsequent sections of this chapter will provide further details on all +available features. + +[source,java,indent=0] +.A first test case +---- +include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +---- + +[[writing-tests-annotations]] +=== Annotations + +JUnit Jupiter supports the following annotations for configuring tests and extending the +framework. + +Unless otherwise stated, all core annotations are located in the `{api-package}` package +in the `junit-jupiter-api` module. + +`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, +this annotation does not declare any attributes, since test extensions in JUnit Jupiter +operate based on their own dedicated annotations. Such methods are inherited unless they +are overridden. + +`*@ParameterizedTest*`:: Denotes that a method is a +<>. Such methods are inherited +unless they are overridden. + +`*@RepeatedTest*`:: Denotes that a method is a test template for a +<>. Such methods are inherited unless they +are overridden. + +`*@TestFactory*`:: Denotes that a method is a test factory for +<>. Such methods are inherited unless they are +overridden. + +`*@TestTemplate*`:: Denotes that a method is a +<> designed to be invoked multiple +times depending on the number of invocation contexts returned by the registered +<>. Such methods are inherited unless they are +overridden. + +`*@TestClassOrder*`:: Used to configure the +<> for `@Nested` +test classes in the annotated test class. Such annotations are inherited. + +`*@TestMethodOrder*`:: Used to configure the +<> for the +annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are +inherited. + +`*@TestInstance*`:: Used to configure the +<> for the annotated test +class. Such annotations are inherited. + +`*@DisplayName*`:: Declares a custom <> for the +test class or test method. Such annotations are not inherited. + +`*@DisplayNameGeneration*`:: Declares a custom +<> for the test class. Such +annotations are inherited. + +`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are +overridden. + +`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current +class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are +overridden. + +`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current +top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are +inherited unless they are overridden and must be `static` unless the "per-class" +<> is used. + +`*@ParameterizedClass*`:: Denotes that the annotated class is a +<>. Such annotations are +inherited. + +`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _before_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be +executed once _after_ each invocation of a +<>. Such methods are inherited +unless they are overridden. + +`*@ClassTemplate*`:: Denotes that the annotated class is a +<> designed to be executed +multiple times depending on the number of invocation contexts returned by the registered +<>. Such annotations are inherited. + +`*@Nested*`:: Denotes that the annotated class is a non-static +<>. Such annotations are not inherited. + +`*@Tag*`:: Used to declare +<>, either at the class or +method level; analogous to test groups in TestNG or Categories in JUnit 4. Such +annotations are inherited at the class level but not at the method level. + +`*@Disabled*`:: Used to <> a test class or test method; +analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. + +`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be +<> after test +execution. Such fields are inherited. + +`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if +its execution exceeds a given duration. Such annotations are inherited. + +`*@TempDir*`:: Used to supply a +<> via field +injection or parameter injection in a test class constructor, lifecycle method, or test +method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. + +`*@ExtendWith*`:: Used to +<>. Such +annotations are inherited. + +`*@RegisterExtension*`:: Used to +<> via fields. +Such fields are inherited. + +WARNING: Some annotations may currently be _experimental_. Consult the table in +<> for details. + +[[writing-tests-meta-annotations]] +==== Meta-Annotations and Composed Annotations + +JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can +define your own _composed annotation_ that will automatically _inherit_ the semantics of +its meta-annotations. + +For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see +<>), you can create a custom _composed annotation_ +named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for +`@Tag("fast")`. + +[source,java,indent=0] +---- +include::{testDir}/example/Fast.java[tags=user_guide] +---- + +The following `@Test` method demonstrates usage of the `@Fast` annotation. + +[source,java,indent=0] +---- +@Fast +@Test +void myFastTest() { + // ... +} +---- + +You can even take that one step further by introducing a custom `@FastTest` annotation +that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. + +[source,java,indent=0] +---- +include::{testDir}/example/FastTest.java[tags=user_guide] +---- + +JUnit automatically recognizes the following as a `@Test` method that is tagged with +"fast". + +[source,java,indent=0] +---- +@FastTest +void myFastTest() { + // ... +} +---- + +[[writing-tests-definitions]] +=== Definitions + +.Platform Concepts +**** +Container:: +a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). + +Test:: +a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). +**** + +.Jupiter Concepts +**** +Lifecycle Method:: +any method that is directly annotated or meta-annotated with +`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. + +Test Class:: +any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +Test classes must not be `abstract` and must have a single constructor. +Java `record` classes are supported as well. + +Test Method:: +any instance method that is directly annotated or meta-annotated with +`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. +With the exception of `@Test`, these create a _container_ in the test tree that groups +_tests_ or, potentially (for `@TestFactory`), other _containers_. +**** + +[[writing-tests-classes-and-methods]] +=== Test Classes and Methods + +Test methods and lifecycle methods may be declared locally within the current test class, +inherited from superclasses, or inherited from interfaces (see +<>). In addition, test methods and +lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` +methods which are required to return a value). + +[NOTE] +.Class and method visibility +==== +Test classes, test methods, and lifecycle methods are not required to be `public`, but +they must _not_ be `private`. + +It is generally recommended to omit the `public` modifier for test classes, test methods, +and lifecycle methods unless there is a technical reason for doing so – for example, when +a test class is extended by a test class in another package. Another technical reason for +making classes and methods `public` is to simplify testing on the module path when using +the Java Module System. +==== + +[NOTE] +.Field and method inheritance +==== +Fields in test classes are inherited. For example, a `@TempDir` field from a superclass +will always be applied in a subclass. + +Test methods and lifecycle methods are inherited unless they are overridden according to +the visibility rules of the Java language. For example, a `@Test` method from a superclass +will always be applied in a subclass unless the subclass explicitly overrides the method. +Similarly, if a package-private `@Test` method is declared in a superclass that resides in +a different package than the subclass, that `@Test` method will always be applied in the +subclass since the subclass cannot override a package-private method from a superclass in +a different package. + +See also: <> +==== + +The following test class demonstrates the use of `@Test` methods and all supported +lifecycle methods. For further information on runtime semantics, see +<> and +<>. + +[source,java,indent=0] +.A standard Java test class +---- +include::{testDir}/example/StandardTests.java[tags=user_guide] +---- + +It is also possible to use Java `record` classes as test classes as illustrated by the +following example. + +[source,java,indent=0] +.A test class written as a Java record +---- +include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +---- + +Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` +keyword for testing code using coroutines. + +[source,kotlin] +.A test class written in Kotlin +---- +include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +---- + +NOTE: Using suspending functions as test or lifecycle methods requires +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], +https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], +and +https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] +to be present on the classpath or module path. + +[[writing-tests-display-names]] +=== Display Names + +Test classes and test methods can declare custom display names via `@DisplayName` -- with +spaces, special characters, and even emojis -- that will be displayed in test reports and +by test runners and IDEs. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +---- + +[NOTE] +==== +Control characters in text-based arguments in display names for parameterized tests are +escaped by default. See <> +for details. + +Any remaining ISO control characters in a display name will be replaced as follows. + +[cols="25%,15%,60%"] +|=== +| Original | Replacement | Description + +| ```\r``` +| `````` +| Textual representation of a carriage return + +| ```\n``` +| `````` +| Textual representation of a line feed + +| Other control character +| ```�``` +| Unicode replacement character (U+FFFD) +|=== +==== + +[[writing-tests-display-name-generator]] +==== Display Name Generators + +JUnit Jupiter supports custom display name generators that can be configured via the +`@DisplayNameGeneration` annotation. + +Generators can be created by implementing the `DisplayNameGenerator` API. The following +table lists the default display name generators available in Jupiter. + +[cols="20,80"] +|=== +| DisplayNameGenerator | Behavior + +| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. +| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. +| `ReplaceUnderscores` | Replaces underscores with spaces. +| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. +|=== + +NOTE: Values provided via `@DisplayName` annotations always take precedence over display +names generated by a `DisplayNameGenerator`. + +====== +The following example demonstrates the use of the `ReplaceUnderscores` display name +generator. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +---- + +Running the above test class results in the following display names. + +``` +A year is not supported ✔ +├─ if it is zero ✔ +└─ A negative value for year is not supported by the leap year computation. ✔ + ├─ For example, year -1 is not supported. ✔ + └─ For example, year -4 is not supported. ✔ +``` +====== + +====== +With the `IndicativeSentences` display name generator, you can customize the separator and +the underlying generator by using `@IndicativeSentencesGeneration` as shown in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year -> if it is one of the following years ✔ + ├─ Year 2016 is a leap year. ✔ + ├─ Year 2020 is a leap year. ✔ + └─ Year 2048 is a leap year. ✔ +``` +====== + +====== +With `IndicativeSentences`, you can optionally specify custom sentence fragments via the +`@SentenceFragment` annotation as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +---- + +Running the above test class results in the following display names. + +``` +A year is a leap year ✔ +├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ +└─ A year is a leap year, if it is one of the following years ✔ + ├─ 2016 ✔ + ├─ 2020 ✔ + └─ 2048 ✔ +``` +====== + + +[[writing-tests-display-name-generator-default]] +==== Setting the Default Display Name Generator + +You can use the `junit.jupiter.displayname.generator.default` +<> to specify the fully qualified +class name of the `DisplayNameGenerator` you would like to use by default. Just like for +display name generators configured via the `@DisplayNameGeneration` annotation, the +supplied class has to implement the `DisplayNameGenerator` interface. The default display +name generator will be used for all tests unless the `@DisplayNameGeneration` annotation +is present on an enclosing test class or test interface. Values provided via +`@DisplayName` annotations always take precedence over display names generated by a +`DisplayNameGenerator`. + +For example, to use the `ReplaceUnderscores` display name generator by default, you should +set the configuration parameter to the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`DisplayNameGenerator`. + +[[writing-tests-display-name-generator-precedence-rules]] +In summary, the display name for a test class or method is determined according to the +following precedence rules: + +1. value of the `@DisplayName` annotation, if present +2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` + annotation, if present +3. by calling the default `DisplayNameGenerator` configured via the configuration + parameter, if present +4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` + +[[writing-tests-assertions]] +=== Assertions + +JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few +that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions +are `static` methods in the `{Assertions}` class. + +Assertion methods optionally accept the assertion message as their third parameter, which +can be either a `String` or a `Supplier`. + +When using a `Supplier` (e.g., a lambda expression), the message is evaluated +lazily. This can provide a performance benefit, especially if message construction is +complex or time-consuming, as it is only evaluated when the assertion fails. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +---- + +[[writing-tests-assertions-preemptive-timeouts]] +[WARNING] +.Preemptive Timeouts with `assertTimeoutPreemptively()` +==== +The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute +the provided `executable` or `supplier` in a different thread than that of the calling +code. This behavior can lead to undesirable side effects if the code that is executed +within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. + +One common example of this is the transactional testing support in the Spring Framework. +Specifically, Spring's testing support binds transaction state to the current thread (via +a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or +`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components +that participate in transactions, any actions taken by those components will not be rolled +back with the test-managed transaction. On the contrary, such actions will be committed to +the persistent store (e.g., relational database) even though the test-managed transaction +is rolled back. + +Similar side effects may be encountered with other frameworks that rely on +`ThreadLocal` storage. +==== + +[[writing-tests-assertions-kotlin]] +==== Kotlin Assertion Support + +JUnit Jupiter also comes with a few assertion methods that lend themselves well to being +used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level +functions in the `org.junit.jupiter.api` package. + +[source,kotlin,indent=0] +---- +include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +---- + +[[writing-tests-assertions-third-party]] +==== Third-party Assertion Libraries + +Even though the assertion facilities provided by JUnit Jupiter are sufficient for many +testing scenarios, there are times when more power and additional functionality are +desired or required. In such cases, the JUnit team recommends the use of third-party +assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore +free to use the assertion library of their choice. + +For example, the following demonstrates how to use the `assertThat()` support from AssertJ +in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, +you can statically import methods such as `assertThat()`, `assertThatException()`, etc. +from `org.assertj.core.api.Assertions` and then use them in tests like in the +`assertWithAssertJ()` method below. + +[source,java,indent=0] +---- +include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +---- + +[TIP] +.Excluding Jupiter’s Assertions From a Project’s Classpath +==== +If you would like to enforce that all your tests use a certain third-party assertion +library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static +analysis tool that fails the build if Jupiter's `Assertions` class is used. + +[source,xml] +---- + + + + + + + + + + + + + + +---- +==== + +[[writing-tests-assumptions]] +=== Assumptions + +Assumptions are typically used whenever it does not make sense to continue execution of a +given test — for example, if the test depends on something that does not exist in the +current runtime environment. + +* When an assumption is valid, the assumption method does not throw an exception, and + execution of the test continues as usual. +* When an assumption is invalid, the assumption method throws an exception of type + `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead + of marked as a failure. + +JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and +adds a few that lend themselves well to being used with Java lambda expressions and method +references. + +All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. + +[source,java,indent=0] +---- +include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +---- + +NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for +assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` +to signal that a test should be aborted instead of marked as a failure. + +TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. +To do so, you can statically import the `assumeThat()` method from +`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your +assumptions. + +[[writing-tests-exceptions]] +=== Exception Handling + +JUnit Jupiter provides robust support for handling test exceptions. This includes the +built-in mechanisms for managing test failures due to exceptions, the role of exceptions +in implementing assertions and assumptions, and how to specifically assert non-throwing +conditions in code. + +[[writing-tests-exceptions-uncaught]] +==== Uncaught Exceptions + +In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an +extension and not caught within that test method, lifecycle method, or extension, the +framework will mark the test or test class as failed. + +[TIP] +==== +Failed assumptions deviate from this general rule. + +In contrast to failed assertions, failed assumptions do not result in a test failure; +rather, a failed assumption results in a test being aborted. + +See <> for further details and examples. +==== + +In the following example, the `failsDueToUncaughtException()` method throws an +`ArithmeticException`. Since the exception is not caught within the test method, JUnit +Jupiter will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +---- + +NOTE: It's important to note that specifying a `throws` clause in the test method has +no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause +as an expectation or assertion about what exceptions the test method should throw. A test +fails only if an exception is thrown unexpectedly or if an assertion fails. + +[[writing-tests-exceptions-failed-assertions]] +==== Failed Assertions + +Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set +of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw +`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit +handles assertion failures as exceptions. See the <> section for +further information about JUnit Jupiter's assertion support. + +NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a +failed assertion; however, they may also choose to throw different types of exceptions to +signal failures. See also: <>. + +TIP: JUnit Jupiter itself does not differentiate between failed assertions +(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test +failure. However, Integrated Development Environments (IDEs) and other tools may +distinguish between these two types of failures by checking whether the thrown exception +is an instance of `AssertionError`. + +In the following example, the `failsDueToUncaughtAssertionError()` method throws an +`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter +will mark the test as failed. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected]] +==== Asserting Expected Exceptions + +JUnit Jupiter offers specialized assertions for testing that specific exceptions are +thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` +assertions are critical tools for validating that your code responds correctly to error +conditions by throwing the appropriate exceptions. + +[[writing-tests-exceptions-expected-assertThrows]] +===== Using `assertThrows()` + +The `assertThrows()` method is used to verify that a particular type of exception is +thrown during the execution of a provided executable block. It not only checks for the +type of the thrown exception but also its subclasses, making it suitable for more +generalized exception handling tests. The `assertThrows()` assertion method returns the +thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-expected-assertThrowsExactly]] +===== Using `assertThrowsExactly()` + +The `assertThrowsExactly()` method is used when you need to assert that the exception +thrown is exactly of a specific type, not allowing for subclasses of the expected +exception type. This is useful when precise exception handling behavior needs to be +validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also +returns the thrown exception object to allow performing additional assertions on it. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +---- + +[[writing-tests-exceptions-not-expected]] +==== Asserting That no Exception is Expected + +Although any exception thrown from a test method will cause the test to fail, there are +certain use cases where it can be beneficial to explicitly assert that an exception is +_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` +assertion can be used when you want to verify that a particular piece of code does not +throw any exceptions. + +[source,java,indent=0] +---- +include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +---- + +NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ +has `assertThatNoException().isThrownBy(() -> ...)`. See also: +<>. + +[[writing-tests-disabling]] +=== Disabling Tests + +Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` +annotation, via one of the annotations discussed in +<>, or via a custom <>. + +When `@Disabled` is applied at the class level, all test methods within that class are +automatically disabled as well. + +If a test method is disabled via `@Disabled`, that prevents execution of the test method +and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, +and corresponding extension APIs. However, that does not prevent the test class from being +instantiated, and it does not prevent the execution of class-level lifecycle callbacks +such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. + +Here's a `@Disabled` test class. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +---- + +And here's a test class that contains a `@Disabled` test method. + +[source,java,indent=0] +---- +include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +---- + +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team +recommends that developers provide a short explanation for why a test class or test +method has been disabled. Consequently, the above examples both show the use of a reason +-- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development +teams even require the presence of issue tracking numbers in the _reason_ for automated +traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + + +[[writing-tests-conditional-execution]] +=== Conditional Test Execution + +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). + +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. + +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. + +See <> and the following sections for +details. + +[TIP] +.Composed Annotations +==== +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. +==== + +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== + +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions + +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. + +[[writing-tests-conditional-execution-os-demo]] +[source,java,indent=0] +.Conditional execution based on operating system +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +---- + +[[writing-tests-conditional-execution-architectures-demo]] +[source,java,indent=0] +.Conditional execution based on architecture +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +---- + +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions + +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. + +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +---- + +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. + +The following listing demonstrates the use of these annotations with arbitrary Java +versions. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +---- + +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions + +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +---- + +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions + +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +---- + +[TIP] +==== +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions + +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +---- + +[TIP] +==== +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. +==== + +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions + +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. + +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. + +[source,java,indent=0] +---- +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +---- + +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- + +[NOTE] +==== +There are several cases where a condition method would need to be `static`: + +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class + +In any other case, you can use either static methods or instance methods as condition +methods. +==== + +[TIP] +==== +It is often the case that you can use an existing static method in a utility class as a +custom condition. + +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. + +[source,java,indent=0] +---- +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") +---- +==== + +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering + +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. + +[source,java,indent=0] +---- +include::{testDir}/example/TaggingDemo.java[tags=user_guide] +---- + +TIP: See <> for examples demonstrating how to create +custom annotations for tags. + +[[writing-tests-test-execution-order]] +=== Test Execution Order + +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. + +NOTE: See <> for a definition of _test method_ and _test class_. + +[[writing-tests-test-execution-order-methods]] +==== Method Order + +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. + +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. + +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ + +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. + +NOTE: See also: <> + +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer + +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. + +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation +---- + +Similarly, you can specify the fully qualified name of any custom class that implements +`MethodOrderer`. + +[[writing-tests-test-execution-order-classes]] +==== Class Order + +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. + +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases + +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. + +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. + +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ + +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): + +[source,properties,indent=0] +---- +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation +---- + +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. + +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. + +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. + +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +---- + +[[writing-tests-test-instance-lifecycle]] +=== Test Instance Lifecycle + +In order to allow individual test methods to be executed in isolation and to avoid +unexpected side effects due to mutable test instance state, JUnit creates a new instance +of each test class before executing each _test method_ (see +<>). This "per-method" test instance lifecycle is the default +behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. + +NOTE: Please note that the test class will still be instantiated if a given _test method_ +is _disabled_ via a <> (e.g., `@Disabled`, +`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. + +If you would prefer that JUnit Jupiter execute all test methods on the same test +instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using +this mode, a new test instance will be created once per test class. Thus, if your test +methods rely on state stored in instance variables, you may need to reset that state in +`@BeforeEach` or `@AfterEach` methods. + +The "per-class" mode has some additional benefits over the default "per-method" mode. +Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and +`@AfterAll` on non-static methods as well as on interface `default` methods. + +If you are authoring tests using the Kotlin programming language, you may also find it +easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as +`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle +mode. + +[[writing-tests-test-instance-lifecycle-changing-default]] +==== Changing the Default Test Instance Lifecycle + +If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter +will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; +however, it is possible to change the _default_ for the execution of an entire test plan. +To change the default test instance lifecycle mode, set the +`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of +an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied +as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, +you can start your JVM with the following system property. + +`-Djunit.jupiter.testinstance.lifecycle.default=per_class` + +Note, however, that setting the default test instance lifecycle mode via the JUnit +Platform configuration file is a more robust solution since the configuration file can be +checked into a version control system along with your project and can therefore be used +within IDEs and your build software. + +To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit +Platform configuration file, create a file named `junit-platform.properties` in the root +of the class path (e.g., `src/test/resources`) with the following content. + +`junit.jupiter.testinstance.lifecycle.default = per_class` + +WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable +results and fragile builds if not applied consistently. For example, if the build +configures "per-class" semantics as the default but tests in the IDE are executed using +"per-method" semantics, that can make it difficult to debug errors that occur on the +build server. It is therefore recommended to change the default in the JUnit Platform +configuration file instead of via a JVM system property. + +[[writing-tests-nested]] +=== Nested Tests + +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. + +[source,java,indent=0] +.Nested test suite for testing a stack +---- +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +---- + +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. + +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] + +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. + +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. + +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. + +[[writing-tests-nested-interoperability]] +==== Interoperability + +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. + +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +---- + +Executing the above test class yields the following output: + +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... + +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods + +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. + +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. + +There are currently three built-in resolvers that are registered automatically. + +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. + +[source,java,indent=0] +---- +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +---- + +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. + +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. + +[source,java,indent=0] +---- +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +---- + +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. + +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. + +[source,java,indent=0] +---- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { + + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } + + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } + +} +---- + +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. + +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods + +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. + +[source,java] +---- +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +---- + +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. + +[source,java] +---- +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +---- + +In your test class you can then implement these test interfaces to have them applied. + +[source,java] +---- +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +---- + +Running the `TestInterfaceDemo` results in output similar to the following: + +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... + +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. + +[source,java] +---- +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +---- + +[source,java] +---- +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +---- + +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. + +[source,java] +---- +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +---- + +NOTE: The above tests are merely meant as examples and therefore not complete. + + +[[writing-tests-repeated-tests]] +=== Repeated Tests + +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. + +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. + +[source,java] +---- +@RepeatedTest(10) +void repeatedTest() { + // ... +} +---- + +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. + +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. + +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. + +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. + +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. + +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions + +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. + +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. + +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples + +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. + +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. + +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. + +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. + +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. + +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. + +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... + +[source,java] +---- +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +---- + +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. + +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... + + +[[writing-tests-parameterized-tests]] +=== Parameterized Classes and Tests + +_Parameterized tests_ make it possible to run a test method multiple times with different +arguments. They are declared just like regular `@Test` methods but use the +`{ParameterizedTest}` annotation instead. + +_Parameterized classes_ make it possible to run _all_ tests in a test class, including +<>, multiple times with different arguments. They are declared just +like regular test classes and may contain any supported test method type (including +`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. + +WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +Regardless of whether you are parameterizing a test method or a test class, you must +declare at least one <> that will +provide the arguments for each invocation and then +<> the arguments in the +parameterized method or class, respectively. + +The following example demonstrates a parameterized test that uses the `@ValueSource` +annotation to specify a `String` array as the source of arguments. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +---- + +When executing the above parameterized test method, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +palindromes(String) ✔ +├─ [1] candidate = "racecar" ✔ +├─ [2] candidate = "radar" ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ +.... + +The same `@ValueSource` annotation can be used to specify the source of arguments for a +`@ParameterizedClass`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +---- + +When executing the above parameterized test class, each invocation will be reported +separately. For instance, the `ConsoleLauncher` will print output similar to the +following. + +.... +PalindromeTests ✔ +├─ [1] candidate = "racecar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +├─ [2] candidate = "radar" ✔ +│ ├─ palindrome() ✔ +│ └─ reversePalindrome() ✔ +└─ [3] candidate = "able was I ere I saw elba" ✔ + ├─ palindrome() ✔ + └─ reversePalindrome() ✔ +.... + +[[writing-tests-parameterized-tests-setup]] +==== Required Setup + +In order to use parameterized classes or tests you need to add a dependency on the +`junit-jupiter-params` artifact. Please refer to <> for details. + +[[writing-tests-parameterized-tests-consuming-arguments]] +==== Consuming Arguments + +[[writing-tests-parameterized-tests-consuming-arguments-methods]] +===== Parameterized Tests + +Parameterized test methods _consume_ arguments directly from the configured source (see +<>) following a one-to-one correlation between +argument source index and method parameter index (see examples in +<>). However, a parameterized test +method may also choose to _aggregate_ arguments from the source into a single object +passed to the method (see <>). +Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an +instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method +must declare formal parameters according to the following rules. + +* Zero or more _indexed parameters_ must be declared first. +* Zero or more _aggregators_ must be declared next. +* Zero or more arguments supplied by a `ParameterResolver` must be declared last. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the +parameterized method at the same index in the method's formal parameter list. An +_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated +with `{AggregateWith}`. + +[[writing-tests-parameterized-tests-consuming-arguments-classes]] +===== Parameterized Classes + +Parameterized classes _consume_ arguments directly from the configured source (see +<>); either via their unique constructor or via +field injection. If a `{Parameter}`-annotated field is declared in the parameterized class +or one of its superclasses, field injection will be used. Otherwise, constructor injection +will be used. + +[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +====== Constructor Injection + +WARNING: Constructor injection can only be used with the (default) `PER_METHOD` +<> mode. Please use +<> +with the `PER_CLASS` mode instead. + +For constructor injection, the same rules apply as defined for +<> +above. In the following example, two arguments are injected into the constructor of the +test class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +---- + +You may use _records_ to implement parameterized classes that avoid the boilerplate code +of declaring a test class constructor. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +---- + +[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +====== Field Injection + +For field injection, the following rules apply for fields annotated with `@Parameter`. + +* Zero or more _indexed parameters_ may be declared; each must have a unique index + specified in its `@Parameter(index)` annotation. The index may be omitted if there is + only one indexed parameter. If there are at least two indexed parameter declarations, + there must be declarations for all indexes from 0 to the largest declared index. +* Zero or more _aggregators_ may be declared; each without specifying an index in its + `@Parameter` annotation. +* Zero or more other fields may be declared as usual as long as they're not annotated with + `@Parameter`. + +In this context, an _indexed parameter_ is an argument for a given index in the +`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated +with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type +{ArgumentsAccessor} or any field annotated with {AggregateWith}. + +The following example demonstrates how to use field injection to consume multiple +arguments in a parameterized class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +---- + +If field injection is used, no constructor parameters will be resolved with arguments from +the source. Other <> +may resolve constructor parameters as usual, though. + +[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +====== Lifecycle Methods + +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also +be used to consume arguments if their `injectArguments` attribute is set to `true` (the +default). If so, their method signatures must follow the same rules apply as defined for +<> and +additionally use the same parameter types as the _indexed parameters_ of the parameterized +test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and +`{AfterParameterizedClassInvocation}` for details and to the +<> section for an +example. + +[NOTE] +.AutoCloseable arguments +==== +Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends +`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or +test invocation. + +To prevent this from happening, set the `autoCloseArguments` attribute in +`@ParameterizedTest` to `false`. Specifically, if an argument that implements +`AutoCloseable` is reused for multiple invocations of the same parameterized class or test +method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or +`{ParameterizedTest}` annotation to ensure that the argument is not closed between +invocations. +==== + +[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +===== Other Extensions + +Other extensions can access the parameters and resolved arguments of a parameterized test +or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. +Please refer to the Javadoc of `{ParameterInfo}` for details. + +[[writing-tests-parameterized-tests-sources]] +==== Sources of Arguments + +Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the +following subsections provides a brief overview and an example for each of them. Please +refer to the Javadoc in the `{params-provider-package}` package for additional +information. + +TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` +and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only +show how to use them with `{ParameterizedTest}` methods. + +[[writing-tests-parameterized-tests-sources-ValueSource]] +===== @ValueSource + +`@ValueSource` is one of the simplest possible sources. It lets you specify a single +array of literal values and can only be used for providing a single argument per +parameterized test invocation. + +The following types of literal values are supported by `@ValueSource`. + +- `short` +- `byte` +- `int` +- `long` +- `float` +- `double` +- `char` +- `boolean` +- `java.lang.String` +- `java.lang.Class` + +For example, the following `@ParameterizedTest` method will be invoked three times, with +the values `1`, `2`, and `3` respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] +---- + +[[writing-tests-parameterized-tests-sources-null-and-empty]] +===== Null and Empty Sources + +In order to check corner cases and verify proper behavior of our software when it is +supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our +parameterized tests. The following annotations serve as sources of `null` and empty values +for parameterized tests that accept a single argument. + +* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` + or `@ParameterizedTest`. + - `@NullSource` cannot be used for a parameter that has a primitive type. +* `{EmptySource}`: provides a single _empty_ argument to the annotated + `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: + `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg + constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, + `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg + constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., + `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). +* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of + `@NullSource` and `@EmptySource`. + +If you need to supply multiple varying types of _blank_ strings to a parameterized +class or test, you can achieve that using +<> -- for example, +`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. + +You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider +range of `null`, _empty_, and _blank_ input. The following example demonstrates how to +achieve this for strings. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] +---- + +Making use of the composed `@NullAndEmptySource` annotation simplifies the above as +follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] +---- + +NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method +result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit +blank strings supplied via `@ValueSource`. + +[[writing-tests-parameterized-tests-sources-EnumSource]] +===== @EnumSource + +`@EnumSource` provides a convenient way to use `Enum` constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] +---- + +The annotation's `value` attribute is optional. When omitted, the declared type of the +first parameter is used. The test will fail if it does not reference an enum type. +Thus, the `value` attribute is required in the above example because the method parameter +is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't +an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the +explicit enum type from the annotation as follows. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] +---- + +The annotation provides an optional `names` attribute that lets you specify which +constants shall be used, like in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] +---- + +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + +The `@EnumSource` annotation also provides an optional `mode` attribute that enables +fine-grained control over which constants are passed to the test method. For example, you +can exclude names from the enum constant pool or specify regular expressions as in the +following examples. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] +---- + +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + +[[writing-tests-parameterized-tests-sources-MethodSource]] +===== @MethodSource + +`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class +or external classes. + +Factory methods within the test class must be `static` unless the test class is annotated +with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes +must always be `static`. + +Each factory method must generate a _stream_ of _arguments_, and each set of arguments +within the stream will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this +translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual +concrete return type can take on many forms. In this context, a "stream" is anything that +JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, +`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or +primitives, or any type that provides an `iterator(): Iterator` method (such as, for +example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied +as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value +if the parameterized class or test method accepts a single argument. + +If the return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +If you only need a single parameter, you can return a `Stream` of instances of the +parameter type as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] +---- + +For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is +mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method +name, JUnit Jupiter will search for a _factory_ method with the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] +---- + +Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also +supported as demonstrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] +---- + +If a parameterized class or test method declares multiple parameters, you need to return a +collection, stream, or array of `Arguments` instances or object arrays as shown below (see +the Javadoc for `{MethodSource}` for further details on supported return types). Note that +`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In +addition, `Arguments.of(Object...)` may be used as an alternative to +`arguments(Object...)`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] +---- + +An external, `static` _factory_ method can be referenced by providing its _fully qualified +method name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +package example; + +include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] +---- + +Factory methods can declare parameters, which will be provided by registered +implementations of the `ParameterResolver` extension API. In the following example, the +factory method is referenced by its name since there is only one such method in the test +class. If there are several local methods with the same name, parameters can also be +provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or +`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method +can be referenced by its fully qualified method name, e.g. +`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. + +[source,java,indent=0] +---- +include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] +---- + +[[writing-tests-parameterized-tests-sources-FieldSource]] +===== @FieldSource + +`{FieldSource}` allows you to refer to one or more fields of the test class or external +classes. + +Fields within the test class must be `static` unless the test class is annotated with +`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be +`static`. + +Each field must be able to supply a _stream_ of arguments, and each set of "arguments" +within the "stream" will be provided as the physical arguments for individual invocations +of the annotated `@ParameterizedClass` or `@ParameterizedTest`. + +In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; +however, the actual concrete field type can take on many forms. Generally speaking this +translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, +`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of +objects or primitives, or any type that provides an `iterator(): Iterator` method (such +as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the +"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, +`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts +a single argument. + +[WARNING] +==== +In contrast to the supported return types for +<> factory +methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, +`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types +are _consumed_ the first time they are processed. However, if you wish to use one of +these types, you can wrap it in a `Supplier` — for example, `Supplier`. +==== + +If the `Supplier` return type is `Stream` or one of the primitive streams, +JUnit will properly close it by calling `BaseStream.close()`, +making it safe to use a resource such as `Files.lines()`. + +Please note that a one-dimensional array of objects supplied as a set of "arguments" will +be handled differently than other types of arguments. Specifically, all the elements of a +one-dimensional array of objects will be passed as individual physical arguments to the +`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for +further details. + +For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a +`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will +search in the test class for a field that has the same name as the current +`@ParameterizedTest` method by convention. This is demonstrated in the following example. +This parameterized test method will be invoked twice: with the values `"apple"` and +`"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] +---- + +The following example demonstrates how to provide a single explicit field name via +`@FieldSource`. This parameterized test method will be invoked twice: with the values +`"apple"` and `"banana"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] +---- + +The following example demonstrates how to provide multiple explicit field names via +`@FieldSource`. This example uses the `listOfFruits` field from the previous example as +well as the `additionalFruits` field. Consequently, this parameterized test method will +be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and +`"dewberry"`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] +---- + +It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or +`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or +iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates +how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test +method will be invoked twice: with the values `"apple"` and `"banana"` and with display +names `"Apple"` and `"Banana"`, respectively. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +If a parameterized class or test method declares multiple parameters, the corresponding +`@FieldSource` field must be able to provide a collection, stream supplier, or array of +`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` +for further details on supported types). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] +---- + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +An external, `static` `@FieldSource` field can be referenced by providing its +_fully qualified field name_ as demonstrated in the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] +---- + +[[writing-tests-parameterized-tests-sources-CsvSource]] +===== @CsvSource + +`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV +`String` literals). Each string provided via the `value` attribute in `@CsvSource` +represents a CSV record and results in one invocation of the parameterized class or +test. The first record may optionally be used to supply CSV headers (see the Javadoc for +the `useHeadersInDisplayName` attribute for details and an example). + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] +---- + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be +changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example +above and in the table below. An empty, quoted value (`''`) results in an empty `String` +unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is +interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value +can be interpreted as a `null` reference (see the `NIL` example in the table below). An +`ArgumentConversionException` is thrown if the target type of a `null` reference is a +primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[cols="50,50"] +|=== +| Example Input | Resulting Argument List + +| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` +| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` +| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` +| `@CsvSource({ "apple, " })` | `"apple"`, `null` +| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` +| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` +|=== + +If the programming language you are using supports Java _text blocks_ or equivalent +multi-line string literals, you can alternatively use the `textBlock` attribute of +`@CsvSource`. Each record within a text block represents a CSV record and results in one +invocation of the parameterized class or test. The first record may optionally be used to +supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the +example below. + +Using a text block, the previous example can be implemented as follows. + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(useHeadersInDisplayName = true, textBlock = """ + FRUIT, RANK + apple, 1 + banana, 2 + 'lemon, lime', 0xF1 + strawberry, 700_000 + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +The generated display names for the previous example include the CSV header names. + +---- +[1] FRUIT = "apple", RANK = "1" +[2] FRUIT = "banana", RANK = "2" +[3] FRUIT = "lemon, lime", RANK = "0xF1" +[4] FRUIT = "strawberry", RANK = "700_000" +---- + +In contrast to CSV records supplied via the `value` attribute, a text block can contain +comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be treated as a comment and ignored. Note that there is one exception +to this rule: if the comment character appears within a quoted field, it loses +its special meaning. + +The comment character must be the first character on the line without any leading +whitespace. It is therefore recommended that the closing text block delimiter (`"""`) +be placed either at the end of the last line of input or on the following line, +left aligned with the rest of the input (as can be seen in the example below which +demonstrates formatting similar to a table). + +[source,java,indent=0] +---- +@ParameterizedTest +@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ + #----------------------------- + # FRUIT | RANK + #----------------------------- + apple | 1 + #----------------------------- + banana | 2 + #----------------------------- + "lemon lime" | 0xF1 + #----------------------------- + strawberry | 700_000 + #----------------------------- + """) +void testWithCsvSource(String fruit, int rank) { + // ... +} +---- + +[NOTE] +==== +Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] +feature automatically removes _incidental whitespace_ when the code is compiled. +However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a +programming language other than Java and your text block contains comments or new lines +within quoted strings, you will need to ensure that there is no leading whitespace within +your text block. +==== + +[[writing-tests-parameterized-tests-sources-CsvFileSource]] +===== @CsvFileSource + +`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the +local file system. Each record from a CSV file results in one invocation of the +parameterized class or test. The first record may optionally be used to supply CSV +headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. +If you would like for the headers to be used in the display names, you can set the +`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of +`numLinesToSkip` and `useHeadersInDisplayName`. + +The default delimiter is a comma (`,`), but you can use another character by setting the +`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a +`String` delimiter instead of a single character. However, both delimiter attributes +cannot be set simultaneously. + +.Comments in CSV files +NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` +by default) will be interpreted as a comment and will be ignored. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] +---- + +[source,csv,indent=0] +.two-column.csv +---- +include::{testResourcesDir}/two-column.csv[] +---- + +The following listing shows the generated display names for the first two parameterized +test methods above. + +---- +[1] country = "Sweden", reference = "1" +[2] country = "Poland", reference = "2" +[3] country = "United States of America", reference = "3" +[4] country = "France", reference = "700_000" +---- + +The following listing shows the generated display names for the last parameterized test +method above that uses CSV header names. + +---- +[1] COUNTRY = "Sweden", REFERENCE = "1" +[2] COUNTRY = "Poland", REFERENCE = "2" +[3] COUNTRY = "United States of America", REFERENCE = "3" +[4] COUNTRY = "France", REFERENCE = "700_000" +---- + +In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double +quote (`+++"+++`) as the quote character by default, but this can be changed via the +`quoteCharacter` attribute. See the `"United States of America"` value in the example +above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the +`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a +`null` reference. By specifying one or more `nullValues`, a custom value can be +interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the +target type of a `null` reference is a primitive type. + +NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless +of any custom values configured via the `nullValues` attribute. + +Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed +by default. This behavior can be changed by setting the +`ignoreLeadingAndTrailingWhitespace` attribute to `true`. + +[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +===== @ArgumentsSource + +`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note +that an implementation of `ArgumentsProvider` must be declared as either a top-level +class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] +---- + +If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation +(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), +you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. + +Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case +they need to be resolved by a registered `ParameterResolver` as demonstrated in the +following example. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] +---- + +[[writing-tests-parameterized-repeatable-sources]] +===== Multiple sources using repeatable annotations + +Repeatable annotations provide a convenient way to specify multiple sources from +different providers. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] +---- + +Following the above parameterized test, a test case will run for each argument: + +---- +[1] foo +[2] bar +---- + +The following annotations are repeatable: + +* `@ValueSource` +* `@EnumSource` +* `@MethodSource` +* `@FieldSource` +* `@CsvSource` +* `@CsvFileSource` +* `@ArgumentsSource` + +[[writing-tests-parameterized-tests-argument-count-validation]] +==== Argument Count Validation + +By default, when an arguments source provides more arguments than the test method needs, +those additional arguments are ignored and the test executes as usual. +This can lead to bugs where arguments are never passed to the parameterized class or +method. + +To prevent this, you can set argument count validation to 'strict'. +Then, any additional arguments will cause an error instead. + +To change this behavior for all tests, set the +`junit.jupiter.params.argumentCountValidation` +<> to `strict`. +To change this behavior for a single parameterized class or test method, +use the `argumentCountValidation` attribute of the `@ParameterizedClass` or +`@ParameterizedTest` annotation: + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] +---- + +[[writing-tests-parameterized-tests-argument-conversion]] +==== Argument Conversion + +[[writing-tests-parameterized-tests-argument-conversion-widening]] +===== Widening Conversion + +JUnit Jupiter supports +https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive +Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. +For example, a parameterized class or test method annotated with +`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type +`int` but also an argument of type `long`, `float`, or `double`. + +[[writing-tests-parameterized-tests-argument-conversion-implicit]] +===== Implicit Conversion + +To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in +implicit type converters. The conversion process depends on the declared type of each +method parameter. + +For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter +of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the +string will be automatically converted into the corresponding `TimeUnit` enum constant. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] +---- + +`String` instances are implicitly converted to the following target types. + +NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their +integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. + +[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[cols="10,90"] +|=== +| Target Type | Example + +| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ +| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` +| `char`/`Character` | `"o"` -> `'o'` +| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` +| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` +| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` +| `float`/`Float` | `"1.0"` -> `1.0f` +| `double`/`Double` | `"1.0"` -> `1.0d` +| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` +| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` +| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ +| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ +| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ +| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` +| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` +| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` +| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` +| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` +| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` +| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` +| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` +| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` +| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` +| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` +| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` +| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` +| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` +| `java.time.Year` | `"2017"` -> `Year.of(2017)` +| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` +| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` +| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` +| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` +| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` +| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` +|=== + +[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +====== Fallback String-to-Object Conversion + +In addition to implicit conversion from strings to the target types listed in the above +table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a +`String` to a given target type if the target type declares exactly one suitable _factory +method_ or a _factory constructor_ as defined below. + +- __factory method__: a non-private, `static` method declared in the target type that + accepts either a single `String` argument or a single `CharSequence` argument and + returns an instance of the target type. The name of the method can be arbitrary and need + not follow any particular convention. +- __factory constructor__: a non-private constructor in the target type that accepts a + either a single `String` argument or a single `CharSequence` argument. Note that the + target type must be declared as either a top-level class or as a `static` nested class. + +NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory +method_ and a _factory constructor_ are discovered, the factory method will be used +instead of the constructor. + +For example, in the following `@ParameterizedTest` method, the `Book` argument will be +created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` +as the title of the book. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] +---- + +[[writing-tests-parameterized-tests-argument-conversion-explicit]] +===== Explicit Conversion + +Instead of relying on implicit argument conversion, you may explicitly specify an +`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation +like in the following example. Note that an implementation of `ArgumentConverter` must be +declared as either a top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] +---- + +If the converter is only meant to convert one type to another, you can extend +`TypedArgumentConverter` to avoid boilerplate type checks. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] +---- + +Explicit argument converters are meant to be implemented by test and extension authors. +Thus, `junit-jupiter-params` only provides a single explicit argument converter that may +also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the +composed annotation `JavaTimeConversionPattern`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] +---- + +If you wish to implement a custom `ArgumentConverter` that also consumes an annotation +(like `JavaTimeArgumentConverter`), you have the possibility to extend the +`{AnnotationBasedArgumentConverter}` class. + +[[writing-tests-parameterized-tests-argument-aggregation]] +==== Argument Aggregation + +By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` +corresponds to a single method parameter. Consequently, argument sources which are +expected to supply a large number of arguments can lead to large constructor or method +signatures, respectively. + +In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using +this API, you can access the provided arguments through a single argument passed to your +test method. In addition, type conversion is supported as discussed in +<>. + +Besides, you can retrieve the current test invocation index with +`ArgumentsAccessor.getInvocationIndex()`. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] +---- + +_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type +`ArgumentsAccessor`._ + +[[writing-tests-parameterized-tests-argument-aggregation-custom]] +===== Custom Aggregators + +Apart from direct access to the arguments of a `@ParameterizedClass` or +`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage +of custom, reusable _aggregators_. + +To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register +it via the `@AggregateWith` annotation on a compatible parameter of the +`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be +provided as an argument for the corresponding parameter when the parameterized test is +invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a +top-level class or as a `static` nested class. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] +---- + +If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for +multiple parameterized classes or methods across your codebase, you may wish to create a +custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with +`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in +action with a custom `@CsvToPerson` annotation. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] +---- + + +[[writing-tests-parameterized-tests-display-names]] +==== Customizing Display Names + +By default, the display name of a parameterized class or test invocation contains the +invocation index and a comma-separated list of the `String` representations of all +arguments for that specific invocation. If parameter names are present in the bytecode, +each argument will be preceded by its parameter name and an equals sign (unless the +argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for +example, `firstName = "Jane"`. + +[TIP] +==== +To ensure that parameter names are present in the bytecode, test code must be compiled +with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag +for Kotlin. +==== + +However, you can customize invocation display names via the `name` attribute of the +`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +Display name of container ✔ +├─ 1 ==> the rank of "apple" is "1" ✔ +├─ 2 ==> the rank of "banana" is "2" ✔ +└─ 3 ==> the rank of "lemon, lime" is "3" ✔ +.... +====== + +[NOTE] +==== +Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to +be represented as a doubled single quote (`''`) in order to be displayed. +==== + +The following placeholders are supported within custom display names. + +[cols="20,80"] +|=== +| Placeholder | Description + +| `\{displayName}` | the display name of the method +| `\{index}` | the current invocation index (1-based) +| `\{arguments}` | the complete, comma-separated arguments list +| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names +| `\{argumentSetName}` | the name of the argument set +| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied +| `\{0}`, `\{1}`, ... | an individual argument +|=== + +NOTE: When including arguments in display names, their string representations are truncated +if they exceed the configured maximum length. The limit is configurable via the +`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults +to 512 characters. + +When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom +names for individual arguments or custom names for entire sets of arguments. + +Use the `{Named}` API to provide a custom name for an individual argument, and the custom +name will be used if the argument is included in the invocation display name, like in the +example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named arguments ✔ +├─ 1: An important file ✔ +└─ 2: Another file ✔ +.... +====== + +[NOTE] +==== +Note that `arguments(Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. + +Similarly, `named(String, Object)` is a static factory method defined in the +`org.junit.jupiter.api.Named` interface. +==== + +Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and +the custom name will be used as the display name, like in the example below. + +====== +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] +---- + +When executing the above method using the `ConsoleLauncher` you will see output similar to +the following. + +.... +A parameterized test with named argument sets ✔ +├─ [1] Important files ✔ +└─ [2] Other files ✔ +.... +====== + +[NOTE] +==== +Note that `argumentSet(String, Object...)` is a static factory method defined in the +`org.junit.jupiter.params.provider.Arguments` interface. +==== + +[[writing-tests-parameterized-tests-display-names-quoted-text]] +===== Quoted Text-based Arguments + +As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are +quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` +is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` +is wrapped in single quotes (`'`). + +Special characters will be escaped in the quoted text. For example, carriage returns and +line feeds will be escaped as `\\r` and `\\n`, respectively. + +[TIP] +==== +This feature can be disabled by setting the `quoteTextArguments` attributes in +`@ParameterizedClass` and `@ParameterizedTest` to `false`. +==== + +For example, given a string argument `"line 1\nline 2"`, the physical representation in +the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. +Similarly, given a string argument `"\t"`, the physical representation in the display name +will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab +character. The same applies for a character argument `'\t'`, whose physical representation +in the display name would be `"'\\t'"` which is printed as `'\t'`. + +For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` +parameterized test method from the +<> section above, the following +display names are generated. + +---- +[1] text = null +[2] text = "" +[3] text = " " +[4] text = " " +[5] text = "\t" +[6] text = "\n" +---- + +If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method +from the <> section above, the +following display names are generated. + +---- +[1] fruit = "apple", rank = "1" +[2] fruit = "banana", rank = "2" +[3] fruit = "lemon, lime", rank = "0xF1" +[4] fruit = "strawberry", rank = "700_000" +---- + +[NOTE] +==== +The original source arguments are quoted when generating a display name, and this occurs +before any implicit or explicit argument conversion is performed. + +For example, if a parameterized test accepts `3.14` as a `float` argument that was +converted from `"3.14"` as an input string, `"3.14"` will be present in the display name +instead of `3.14`. You can see the effect of this with the `rank` values in the above +example. +==== + +[[writing-tests-parameterized-tests-display-names-default-pattern]] +===== Default Display Name Pattern + +If you'd like to set a default name pattern for all parameterized classes and tests in +your project, you can declare the `junit.jupiter.params.displayname.default` configuration +parameter in the `junit-platform.properties` file as demonstrated in the following example (see +<> for other options). + +[source,properties,indent=0] +---- +junit.jupiter.params.displayname.default = {index} +---- + +[[writing-tests-parameterized-tests-display-names-precedence-rules]] +===== Precedence Rules + +The display name for a parameterized class or test is determined according to the +following precedence rules: + +1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present +2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present +3. `DEFAULT_DISPLAY_NAME` constant defined in + `org.junit.jupiter.params.ParameterizedInvocationConstants` + +[[writing-tests-parameterized-tests-lifecycle-interop]] +==== Lifecycle and Interoperability + +[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +===== Parameterized Tests + +Each invocation of a parameterized test has the same lifecycle as a regular `@Test` +method. For example, `@BeforeEach` methods will be executed before each invocation. +Similar to <>, invocations will appear one by one in the +test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` +methods within the same test class. + +You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, +method parameters that are resolved by argument sources need to come first in the +parameter list. Since a test class may contain regular tests as well as parameterized +tests with different parameter lists, values from argument sources are not resolved for +lifecycle methods (e.g. `@BeforeEach`) and test class constructors. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] +---- + +[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +===== Parameterized Classes + +Each invocation of a parameterized class has the same lifecycle as a regular test class. +For example, `@BeforeAll` methods will be executed _once_ before all invocations and +`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to +<>, invocations will appear one by one in the test tree of an +IDE. + +You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. +However, if constructor injection is used, constructor parameters that are resolved by +argument sources need to come first in the parameter list. Values from argument sources +are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). + +In addition to regular lifecycle methods, parameterized classes may declare +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle +methods that are called once before/after each invocation of the parameterized class. +These methods must be `static` unless the parameterized class is configured to use +`@TestInstance(Lifecycle.PER_CLASS)` (see <>). + +These lifecycle methods may optionally declare parameters that are resolved depending on +the setting of the `injectArguments` annotation attribute. If it is set to `false`, the +parameters must be resolved by other registered {ParameterResolver} extensions. If the +attribute is set to `true` (the default), the method may declare parameters that match the +arguments of the parameterized class (see the Javadoc of +`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for +details). This may, for example, be used to initialize the used arguments as demonstrated +by the following example. + +[source,java,indent=0] +.Using parameterized class lifecycle methods +---- +include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] +---- +<1> Initialization of the argument _before_ each invocation of the parameterized class +<2> Usage of the previously initialized argument in a test method +<3> Validation and cleanup of the argument _after_ each invocation of the parameterized + class + +[[writing-tests-class-templates]] +=== Class Templates + +A `{ClassTemplate}` is not a regular test class but rather a template for the contained +test cases. As such, it is designed to be invoked multiple times depending on invocation +contexts returned by the registered providers. Thus, it must be used in conjunction with a +registered `{ClassTemplateInvocationContextProvider}` extension. +Each invocation of a class template behaves like the execution of a regular test class +with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> are a built-in +specialization of class templates. + +[[writing-tests-test-templates]] +=== Test Templates + +A `{TestTemplate}` method is not a regular test case but rather a template for a test +case. As such, it is designed to be invoked multiple times depending on the number of +invocation contexts returned by the registered providers. Thus, it must be used in +conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each +invocation of a test template method behaves like the execution of a regular `@Test` +method with full support for the same lifecycle callbacks and extensions. Please refer to +<> for usage examples. + +NOTE: <> and +<> are built-in specializations of +test templates. + +[[writing-tests-dynamic-tests]] +=== Dynamic Tests + +The standard `@Test` annotation in JUnit Jupiter described in +<> is very similar to the `@Test` annotation in JUnit 4. Both +describe methods that implement test cases. These test cases are static in the sense that +they are fully specified at compile time, and their behavior cannot be changed by +anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but +are intentionally rather limited in their expressiveness._ + +In addition to these standard tests a completely new kind of test programming model has +been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is +generated at runtime by a factory method that is annotated with `@TestFactory`. + +In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but +rather a factory for test cases. Thus, a dynamic test is the product of a factory. +Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a +_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" +is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, +`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an +`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). + +Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. +`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child +nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. +`DynamicTest` instances will be executed lazily, enabling dynamic and even +non-deterministic generation of test cases. + +Any `Stream` returned by a `@TestFactory` will be properly closed by calling +`stream.close()`, making it safe to use a resource such as `Files.lines()`. + +As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may +optionally declare parameters to be resolved by `ParameterResolvers`. + +A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ +and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the +implementations of dynamic tests can be provided as _lambda expressions_ or _method +references_. + +.Dynamic Test Lifecycle +WARNING: The execution lifecycle of a dynamic test is quite different than it is for a +standard `@Test` case. Specifically, there are no lifecycle callbacks for individual +dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their +corresponding extension callbacks are executed for the `@TestFactory` method but not for +each _dynamic test_. In other words, if you access fields from the test instance within a +lambda expression for a dynamic test, those fields will not be reset by callback methods +or extensions between the execution of individual dynamic tests generated by the same +`@TestFactory` method. + +[[writing-tests-dynamic-tests-examples]] +==== Dynamic Test Examples + +The following `DynamicTestsDemo` class demonstrates several examples of test factories +and dynamic tests. + +The first method returns an invalid return type and will cause a warning to be reported by +JUnit during test discovery. Such methods are not executed. + +The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, +array, or `Stream` of `DynamicTest` instances. Most of these examples do not really +exhibit dynamic behavior but merely demonstrate the supported return types in principle. +However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to +generate dynamic tests for a given set of strings or a range of input numbers. + +The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an +`Iterator` that generates random numbers, a display name generator, and a test executor +and then provides all three to `DynamicTest.stream()`. Although the non-deterministic +behavior of `generateRandomNumberOfTests()` is of course in conflict with test +repeatability and should thus be used with care, it serves to demonstrate the +expressiveness and power of dynamic tests. + +The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; +however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from +an existing `Stream` via the `DynamicTest.stream()` factory method. + +For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single +`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates +a nested hierarchy of dynamic tests utilizing `DynamicContainer`. + +[source,java] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-named-support]] +==== Dynamic Tests and Named + +In some cases, it can be more natural to specify inputs together with a descriptive name +using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as +shown in the first example below. The second example takes it one step further and allows +to provide the code block that should be executed by implementing the `Executable` +interface along with `Named` via the `NamedExecutable` base class. + +[source,java] +---- +include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +---- + +[[writing-tests-dynamic-tests-uri-test-source]] +==== URI Test Sources for Dynamic Tests + +The JUnit Platform provides `TestSource`, a representation of the source of a test or +container used to navigate to its location by IDEs and build tools. + +The `TestSource` for a dynamic test or dynamic container can be constructed from a +`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, +Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, +respectively. The `URI` will be converted to one of the following `TestSource` +implementations. + +`ClasspathResourceSource` :: + If the `URI` contains the `classpath` scheme -- for example, + `classpath:/test/foo.xml?line=20,column=2`. + +`DirectorySource` :: + If the `URI` represents a directory present in the file system. + +`FileSource` :: + If the `URI` represents a file present in the file system. + +`MethodSource` :: + If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- + for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please + refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the + supported formats for a FQMN. + +`ClassSource` :: + If the `URI` contains the `class` scheme and the fully qualified class name -- + for example, `class:org.junit.Foo?line=42`. + +`UriSource` :: + If none of the above `TestSource` implementations are applicable. + +[[writing-tests-dynamic-tests-parallel-execution]] +==== Parallel Execution + +Dynamic tests and containers support +<>. You can configure their +`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` +factory methods as illustrated by the following example. + +[source,java,indent=0] +---- +include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +---- + +Executing the above test factory method results in the following test tree and execution +modes: + +* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) +** Container A -- `CONCURRENT` (from `@Execution` annotation) +*** not null -- `SAME_THREAD` (from `executionMode(...)` call) +*** properties -- `CONCURRENT` (from `@Execution` annotation) +**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) +**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) +** ... (same for "Container B" and "Container C") + +[[writing-tests-declarative-timeouts]] +=== Timeouts + +The `@Timeout` annotation allows one to declare that a test, test factory, test template, +or lifecycle method should fail if its execution time exceeds a given duration. The time +unit for the duration defaults to seconds but is configurable. + +The following example shows how `@Timeout` is applied to lifecycle and test methods. + +[source,java] +---- +include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +---- + +To apply the same timeout to all test methods within a test class and all of its `@Nested` +classes, you can declare the `@Timeout` annotation at the class level. It will then be +applied to all test, test factory, and test template methods within that class and its +`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or +`@Nested` class. Please note that `@Timeout` annotations declared at the class level are +not applied to lifecycle methods. + +Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns +within the specified duration but does not verify the execution time of each individual +`DynamicTest` generated by the factory. Please use +`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. + +If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or +`@ParameterizedTest` — each invocation will have the given timeout applied to it. + +[[writing-tests-declarative-timeouts-thread-mode]] +==== Thread mode + +The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, +`SEPARATE_THREAD`, or `INFERRED`. + +When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main +thread of the test. If the timeout is exceeded, the main thread is interrupted from +another thread. This is done to ensure interoperability with frameworks such as Spring +that make use of mechanisms that are sensitive to the currently running thread — for +example, `ThreadLocal` transaction management. + +On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` +assertion, the execution of the annotated method proceeds in a separate thread, this +can lead to undesirable side effects, see <>. + +When `INFERRED` (default) thread mode is used, the thread mode is resolved via the +`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the +provided configuration parameter is invalid or not present then `SAME_THREAD` is used as +fallback. + +[[writing-tests-declarative-timeouts-default-timeouts]] +==== Default Timeouts + +The following <> can be used to +specify default timeouts for all methods of a certain category unless they or an enclosing +test class is annotated with `@Timeout`: + +`junit.jupiter.execution.timeout.default`:: + Default timeout for all testable and lifecycle methods +`junit.jupiter.execution.timeout.testable.method.default`:: + Default timeout for all testable methods +`junit.jupiter.execution.timeout.test.method.default`:: + Default timeout for `@Test` methods +`junit.jupiter.execution.timeout.testtemplate.method.default`:: + Default timeout for `@TestTemplate` methods +`junit.jupiter.execution.timeout.testfactory.method.default`:: + Default timeout for `@TestFactory` methods +`junit.jupiter.execution.timeout.lifecycle.method.default`:: + Default timeout for all lifecycle methods +`junit.jupiter.execution.timeout.beforeall.method.default`:: + Default timeout for `@BeforeAll` methods +`junit.jupiter.execution.timeout.beforeeach.method.default`:: + Default timeout for `@BeforeEach` methods +`junit.jupiter.execution.timeout.aftereach.method.default`:: + Default timeout for `@AfterEach` methods +`junit.jupiter.execution.timeout.afterall.method.default`:: + Default timeout for `@AfterAll` methods + +More specific configuration parameters override less specific ones. For example, +`junit.jupiter.execution.timeout.test.method.default` overrides +`junit.jupiter.execution.timeout.testable.method.default` which overrides +`junit.jupiter.execution.timeout.default`. + +The values of such configuration parameters must be in the following, case-insensitive +format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be +omitted. Specifying no unit is equivalent to using seconds. + +.Example timeout configuration parameter values +[cols="20,80"] +|=== +| Parameter value | Equivalent annotation + +| `42` | `@Timeout(42)` +| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` +| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` +| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` +| `42 s` | `@Timeout(value = 42, unit = SECONDS)` +| `42 m` | `@Timeout(value = 42, unit = MINUTES)` +| `42 h` | `@Timeout(value = 42, unit = HOURS)` +| `42 d` | `@Timeout(value = 42, unit = DAYS)` +|=== + + +[[writing-tests-declarative-timeouts-polling]] +==== Using @Timeout for Polling Tests + +When dealing with asynchronous code, it is common to write tests that poll while waiting +for something to happen before performing any assertions. In some cases you can rewrite +the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes +that is not possible — for example, if the subject under test sends a message to a channel +in an external message broker and assertions cannot be performed until the message has +been successfully sent through the channel. Asynchronous tests like these require some +form of timeout to ensure they don't hang the test suite by executing indefinitely, as +would be the case if an asynchronous message never gets successfully delivered. + +By configuring a timeout for an asynchronous test that polls, you can ensure that the test +does not execute indefinitely. The following example demonstrates how to achieve this with +JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll +until" logic very easily. + +[source,java] +---- +include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +---- + +NOTE: If you need more control over polling intervals and greater flexibility with +asynchronous tests, consider using a dedicated library such as +link:https://github.com/awaitility/awaitility[Awaitility]. + + +[[writing-tests-declarative-timeouts-debugging]] +==== Debugging Timeouts + +Registered <> extensions are called prior to invoking +`Thread.interrupt()` on the thread that is executing the timed out method. This allows to +inspect the application state and output additional information that might be helpful for +diagnosing the cause of a timeout. + + +[[writing-tests-declarative-timeouts-debugging-thread-dump]] +===== Thread Dump on Timeout + +JUnit registers a default implementation of the <> +extension point that dumps the stacks of all threads to `System.out` if enabled by setting +the `junit.jupiter.execution.timeout.threaddump.enabled` +<> to `true`. + + +[[writing-tests-declarative-timeouts-mode]] +==== Disable @Timeout Globally + +When stepping through your code in a debug session, a fixed timeout limit may influence +the result of the test, e.g. mark the test as failed although all assertions were met. + +JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter +to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, +and `disabled_on_debug`. The default mode is `enabled`. +A VM runtime is considered to run in debug mode when one of its input parameters starts +with `-agentlib:jdwp` or `-Xrunjdwp`. +This heuristic is queried by the `disabled_on_debug` mode. + + +[[writing-tests-parallel-execution]] +=== Parallel Execution + +By default, JUnit Jupiter tests are run sequentially in a single thread; however, running +tests in parallel -- for example, to speed up execution -- is available as an opt-in +feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` +configuration parameter to `true` -- for example, in `junit-platform.properties` (see +<> for other options). + +Please note that enabling this property is only the first step required to execute tests +in parallel. If enabled, test classes and methods will still be executed sequentially by +default. Whether or not a node in the test tree is executed concurrently is controlled by +its execution mode. The following two modes are available. + +`SAME_THREAD`:: + Force execution in the same thread used by the parent. For example, when used on a test + method, the test method will be executed in the same thread as any `@BeforeAll` or + `@AfterAll` methods of the containing test class. + +`CONCURRENT`:: + Execute concurrently unless a resource lock forces execution in the same thread. + +By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change +the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration +parameter. Alternatively, you can use the `{Execution}` annotation to change the +execution mode for the annotated element and its subelements (if any) which allows you to +activate parallel execution for individual test classes, one by one. + +[source,properties] +.Configuration parameters to execute all tests in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +---- + +The default execution mode is applied to all nodes of the test tree with a few notable +exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a +`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is +thread-safe; in the latter, concurrent execution might conflict with the configured +execution order. Thus, in both cases, test methods in such test classes are only executed +concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or +method. + +You can use the `@Execution` annotation to explicitly configure the execution mode for a +test class or method: + +[source,java] +---- +include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +---- + +This allows test classes or methods to opt in or out of concurrent execution regardless of +the globally configured default. + +When parallel execution is enabled and a default `{ClassOrderer}` is registered (see +<> for details), top-level test classes will +initially be sorted accordingly and scheduled in that order. However, they are not +guaranteed to be started in exactly that order since the threads they are executed on are +not controlled directly by JUnit. + +All nodes of the test tree that are configured with the `CONCURRENT` execution mode will +be executed fully in parallel according to the provided +<> while observing the +declarative <> +mechanism. Please note that <> needs to be enabled +separately. + +In addition, you can configure the default execution mode for top-level classes by setting +the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By +combining both configuration parameters, you can configure classes to run in parallel but +their methods in the same thread: + +[source,properties] +.Configuration parameters to execute top-level classes in parallel but methods in same thread +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +---- + +The opposite combination will run all methods within one class in parallel, but top-level +classes will run sequentially: + +[source,properties] +.Configuration parameters to execute top-level classes sequentially but their methods in parallel +---- +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = same_thread +---- + +The following diagram illustrates how the execution of two top-level test classes `A` and +`B` with two test methods per class behaves for all four combinations of +`junit.jupiter.execution.parallel.mode.default` and +`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). + +//// +Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X + +--- +displayMode: compact +--- + +gantt + dateFormat X + axisFormat %s + tickInterval 1 + title ↓ threads | time → + + section (same_thread, same_thread) + A.test1() :ass1, 0, 1 + A.test2() :ass2, after ass1, 2 + B.test1() :bss1, after ass2, 3 + B.test2() :bss2, after bss1, 4 + + section (same_thread, concurrent) + A.test1() :asc1, 0, 1 + A.test2() :asc2, after asc1, 2 + B.test1() :bsc1, 0, 1 + B.test2() :bsc2, after bsc1, 2 + + section (concurrent, same_thread) + A.test1() :acs1, 0, 1 + A.test2() :acs2, 0, 1 + B.test1() :bcs1, after acs1, 2 + B.test2() :bcs2, after acs2, 2 + + section (concurrent, concurrent) + A.test1() :acc1, 0, 1 + A.test2() :acc2, 0, 1 + B.test1() :bcc1, 0, 1 + B.test2() :bcc2, 0, 1 + +//// +image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] + +If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is +not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be +used instead. + +[[writing-tests-parallel-execution-config]] +==== Configuration + +[[writing-tests-parallel-execution-config-executor-service]] +===== Executor Service + +If parallel execution is enabled, a thread pool is used behind the scenes to execute tests +concurrently. You can configure which implementation of `HierarchicalTestExecutorService` +is used be setting the `junit.jupiter.execution.parallel.config.executor-service` +configuration parameter to one of the following options: + +`fork_join_pool` (default):: +Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause +tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of +`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the +number of concurrently executing tests to increase. To avoid this situation, please use +`worker_thread_pool`. + +`worker_thread_pool` (experimental):: +Use an executor service that is backed by a regular thread pool and does not create +additional threads if test or production code uses `ForkJoinPool` or calls a blocking +API in the JDK. + +WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited +to give it a try and provide feedback to the JUnit team so they can improve and eventually +<> this feature. + +[[writing-tests-parallel-execution-config-strategies]] +===== Strategies + +Properties such as the desired parallelism and the maximum pool size can be configured +using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two +implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a +`custom` strategy. + +To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` +configuration parameter to one of the following options. + +`dynamic`:: + Computes the desired parallelism based on the number of available processors/cores + multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` + configuration parameter (defaults to `1`). + The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` + configuration parameter can be used to limit the maximum number of threads. + +`fixed`:: + Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` + configuration parameter as the desired parallelism. + The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` + configuration parameter can be used to limit the maximum number of threads. + +`custom`:: + Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` + implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` + configuration parameter to determine the desired configuration. + +If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration +strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the +number of available processors/cores. + +.Parallelism alone does not imply maximum number of concurrent threads +NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to +execute test will not exceed the configured parallelism. For example, when using one +of the synchronization mechanisms described in the next section, the executor service +implementation may spawn additional threads to ensure execution continues with sufficient +parallelism. If you require such guarantees, it is possible to limit the maximum number of +threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` +strategies. + +[[writing-tests-parallel-execution-config-properties]] +===== Relevant properties + +The following table lists relevant properties for configuring parallel execution. See +<> for details on how to set such properties. + +====== General + +`junit.jupiter.execution.parallel.enabled=true|false`:: + Enable/disable parallel test execution (defaults to `false`). + +`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: + Default execution mode of nodes in the test tree (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: + Default execution mode of top-level classes (defaults to `same_thread`). + +`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: + Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to + `fork_join_pool`). + +`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: + Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). + +====== Dynamic strategy + +`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: + Factor to be multiplied by the number of available processors/cores to determine the + desired parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number (defaults to `1.0`). + +`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: + Factor to be multiplied by the number of available processors/cores and the value of + `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired + parallelism for the ```dynamic``` configuration strategy. + Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the + number of available processors/cores) + +`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Fixed strategy + +`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: + Desired parallelism for the ```fixed``` configuration strategy (no default value). Must + be a positive integer. + +`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: + Desired maximum pool size of the underlying fork-join pool for the ```fixed``` + configuration strategy. Must be a positive integer greater than or equal to + `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the + value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). + +`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: + Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` + configuration strategy (defaults to `true`). Only used if + `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. + +====== Custom strategy + +`junit.jupiter.execution.parallel.config.custom.class=classname`:: + Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used + for the ```custom``` configuration strategy (no default value). + +[[writing-tests-parallel-execution-synchronization]] +==== Synchronization + +In addition to controlling the execution mode using the `{Execution}` annotation, JUnit +Jupiter provides another annotation-based declarative synchronization mechanism. The +`{ResourceLock}` annotation allows you to declare that a test class or method uses a +specific shared resource that requires synchronized access to ensure reliable test +execution. The shared resource is identified by a unique name which is a `String`. The +name can be user-defined or one of the predefined constants in `{Resources}`: +`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. + +In addition to declaring these shared resources statically, the `{ResourceLock}` +annotation has a `providers` attribute that allows registering implementations of the +`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. +Note that resources declared statically with `{ResourceLock}` annotation are combined with +resources added dynamically by `{ResourceLocksProvider}` implementations. + +If the tests in the following example were run in parallel _without_ the use of +`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they +would fail due to the inherent race condition of writing and then reading the same JVM +System Property. + +When access to shared resources is declared using the `{ResourceLock}` annotation, the +JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in +parallel. This guarantee extends to lifecycle methods of a test class or method. For +example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will +be acquired before any `@BeforeEach` methods are executed and released after all +`@AfterEach` methods have been executed. + +[NOTE] +.Running tests in isolation +==== +If most of your test classes can be run in parallel without any synchronization but you +have some test classes that need to run in isolation, you can mark the latter with the +`{Isolated}` annotation. Tests in such classes are executed sequentially without any other +tests running at the same time. +==== + +In addition to the `String` that uniquely identifies the shared resource, you may specify +an access mode. Two tests that require `READ` access to a shared resource may run in +parallel with each other but not while any other test that requires `READ_WRITE` access +to the same shared resource is running. + +[source,java] +.Declaring shared resources "statically" with `{ResourceLock}` annotation +---- +include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +---- + +[source,java] +.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation +---- +include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +---- + +Also, "static" shared resources can be declared for _direct_ child nodes via the `target` +attribute in the `{ResourceLock}` annotation, the attribute accepts a value from +the `{ResourceLockTarget}` enum. + +Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation +has the same semantics as adding an annotation with the same `value` and `mode` +to each test method and nested test class declared in this class. + +This may improve parallelization when a test class declares a `READ` lock, +but only a few methods hold a `READ_WRITE` lock. + +Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` +didn't have `target = CHILDREN`. This is because the test class declares a `READ` +shared resource, but one test method holds a `READ_WRITE` lock, +which would force the `SAME_THREAD` execution mode for all the test methods. + +[source,java] +.Declaring shared resources for child nodes with `target` attribute +---- +include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +---- + + +[[writing-tests-built-in-extensions]] +=== Built-in Extensions + +While the JUnit team encourages reusable extensions to be packaged and maintained in +separate libraries, JUnit Jupiter includes a few user-facing extension implementations +that are considered so generally useful that users shouldn't have to add another +dependency. + +[[writing-tests-built-in-extensions-TempDirectory]] +==== The @TempDir Extension + +The built-in `{TempDirectory}` extension is used to create and clean up a temporary +directory for an individual test or all tests in a test class. It is registered by +default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or +`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or +`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or +test method. + +For example, the following test declares a parameter annotated with `@TempDir` for a +single test method, creates and writes to a file in the temporary directory, and checks +its content. + +[source,java,indent=0] +.A test method that requires a temporary directory +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +---- + +You can inject multiple temporary directories by specifying multiple annotated parameters. + +[source,java,indent=0] +.A test method that requires multiple temporary directories +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +---- + +The following example stores a _shared_ temporary directory in a `static` field. This +allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of +the test class. For better isolation, you should use an instance field or constructor +injection so that each test method uses a separate directory. + +[source,java,indent=0] +.A test class that shares a temporary directory across test methods +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +---- + +The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either +`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary +directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the +temporary directory will only be deleted after the test if the test completed successfully. + +The default cleanup mode is `ALWAYS`. You can use the +`junit.jupiter.tempdir.cleanup.mode.default` +<> to override this default. + +[source,java,indent=0] +.A test class with a temporary directory that doesn't get cleaned up +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +---- + +`@TempDir` supports the programmatic creation of temporary directories via the optional +`factory` attribute. This is typically used to gain control over the temporary directory +creation, like defining the parent directory or the file system that should be used. + +Factories can be created by implementing `TempDirFactory`. Implementations must provide a +no-args constructor and should not make any assumptions regarding when and how many times +they are instantiated, but they can assume that their `createTempDirectory(...)` and +`close()` methods will both be called once per instance, in this order, and from the same +thread. + +The default implementation available in Jupiter delegates directory creation to +`java.nio.file.Files::createTempDirectory` which uses the default file system and the +system's temporary directory as the parent directory. It passes `junit-` as the prefix +string of the generated directory name to help identify it as a created by JUnit. + +The following example defines a factory that uses the test name as the directory name +prefix instead of the `junit` constant value. + +[source,java,indent=0] +.A test class with a temporary directory having the test name as the directory name prefix +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +---- + +It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the +temporary directory. The following example demonstrates how to achieve that. + +[source,java,indent=0] +.A test class with a temporary directory created with the Jimfs in-memory file system +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +---- + +`@TempDir` can also be used as a <> to +reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` +annotation that can be used as a drop-in replacement for +`@TempDir(factory = JimfsTempDirFactory.class)`. + +[source,java,indent=0] +.A custom annotation meta-annotated with `@TempDir` +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +---- + +The following example demonstrates how to use the custom `@JimfsTempDir` annotation. + +[source,java,indent=0] +.A test class using the custom annotation +---- +include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +---- + +Meta-annotations or additional annotations on the field or parameter the `TempDir` +annotation is declared on might expose additional attributes to configure the factory. +Such annotations and related attributes can be accessed via the `AnnotatedElementContext` +parameter of the `createTempDirectory(...)` method. + +You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +`TempDirFactory` you would like to use by default. Just like for factories configured via +the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement +the `TempDirFactory` interface. The default factory will be used for all `@TempDir` +annotations unless the `factory` attribute of the annotation specifies a different factory. + +In summary, the factory for a temporary directory is determined according to the following +precedence rules: + +1. The `factory` attribute of the `@TempDir` annotation, if present +2. The default `TempDirFactory` configured via the configuration +parameter, if present +3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. + +[[writing-tests-built-in-extensions-AutoClose]] +==== The @AutoClose Extension + +The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. +It is registered by default. To use it, annotate a field in a test class with +`{AutoClose}`. + +`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` +field is `null` when it is evaluated the field will be ignored, but a warning message will +be logged to inform you. + +By default, `@AutoClose` expects the value of the annotated field to implement a `close()` +method that will be invoked to close the resource. However, developers can customize the +name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` +instructs JUnit to look for a `shutdown()` method to close the resource. + +`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from +subclasses will be closed before `@AutoClose` fields in superclasses. + +When multiple `@AutoClose` fields exist within a given test class, the order in which the +resources are closed depends on an algorithm that is deterministic but intentionally +nonobvious. This ensures that subsequent runs of a test suite close resources in the same +order, thereby allowing for repeatable builds. + +The `AutoCloseExtension` implements the `AfterAllCallback` and +`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` +field will be closed after all tests in the current test class have completed, effectively +after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` +field will be closed before the current test class instance is destroyed. Specifically, if +the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a +non-static `@AutoClose` field will be closed after the execution of each test method, test +factory method, or test template method. However, if the test class is configured with +`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not +be closed until the current test class instance is no longer needed, which means after +`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. + +The following example demonstrates how to annotate an instance field with `@AutoClose` so +that the resource is automatically closed after test execution. In this example, we assume +that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. + +[source,java,indent=0] +.A test class using `@AutoClose` to close a resource +---- +include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +---- +<1> Annotate an instance field with `@AutoClose`. +<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that + will be invoked after each `@Test` method. + +[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +==== The @DefaultLocale and @DefaultTimeZone Extensions + +The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values +returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are +often used implicitly when no specific locale or time zone is chosen. Both annotations +work on the test class level and on the test method level, and are inherited from +higher-level containers. After the annotated element has been executed, the initial +default value is restored. + +[[writing-tests-built-in-extensions-DefaultLocale]] +===== @DefaultLocale + +The default `Locale` can be specified using an +{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +---- + +Alternatively, the default `Locale` can be created using the following attributes from +which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] +can create an instance: + +* `language` or +* `language` and `country` or +* `language`, `country`, and `variant` + +NOTE: The variant needs to be a string which follows the +https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +---- + +Mixing language tag configuration (via the annotation's `value` attributed) and +attributed-based configuration will cause an exception to be thrown. Furthermore, a +`variant` can only be specified if `country` is also specified. Otherwise, an exception +will be thrown. + +Any method-level `@DefaultLocale` configurations will override class-level configurations. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +---- + +NOTE: A class-level configuration means that the specified locale is set before and reset +after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{LocaleProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +[[writing-tests-built-in-extensions-DefaultTimeZone]] +===== @DefaultTimeZone + +The default `TimeZone` is specified according to the +{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] +method. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +---- + +Any method level `@DefaultTimeZone` configurations will override class level configurations: + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +---- + +NOTE: A class-level configuration means that the specified time zone is set before and +reset after each individual test in the annotated class. + +If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + +[source,java,indent=0] +---- +include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +---- + +NOTE: The provider implementation must have a no-args (or the default) constructor. + +===== Thread Safety + +Since the default locale and time zone are global state, reading and writing them during +<> can lead to unpredictable +results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are +prepared for that and tests annotated with them will never execute in parallel (thanks to +`{ResourceLock}`) to guarantee correct test results. + +However, this does not cover all possible cases. Tested code that reads or writes default +locale and time zone _independently_ of the extensions can still run in parallel to them +and may thus behave erratically when, for example, it unexpectedly reads a locale set by +the extension in another thread. Tests that cover code that reads or writes the default +locale or time zone need to be annotated with the respective annotation: + +* `{ReadsDefaultLocale}` +* `{ReadsDefaultTimeZone}` +* `{WritesDefaultLocale}` +* `{WritesDefaultTimeZone}` + +Tests annotated in this way will never execute in parallel with tests annotated with +`@DefaultLocale` or `@DefaultTimeZone`. From 5c4e125c08320f9b0552e5d8e19b4f9ab8546ef6 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:09 +0100 Subject: [PATCH 17/57] Migrate writing-tests.adoc sections to Antora --- .../ROOT/pages/writing-tests/annotations.adoc | 3766 --------------- .../ROOT/pages/writing-tests/assertions.adoc | 3841 ---------------- .../ROOT/pages/writing-tests/assumptions.adoc | 3907 ---------------- .../writing-tests/built-in-extensions.adoc | 3644 --------------- .../pages/writing-tests/class-templates.adoc | 3926 ---------------- .../conditional-test-execution.adoc | 3998 +--------------- .../ROOT/pages/writing-tests/definitions.adoc | 3909 ---------------- ...njection-for-constructors-and-methods.adoc | 3980 +--------------- .../pages/writing-tests/disabling-tests.adoc | 3892 ---------------- .../pages/writing-tests/display-names.adoc | 3779 --------------- .../pages/writing-tests/dynamic-tests.adoc | 3783 --------------- .../writing-tests/exception-handling.adoc | 3819 ---------------- .../ROOT/pages/writing-tests/intro.adoc | 3923 ---------------- .../pages/writing-tests/nested-tests.adoc | 3973 +--------------- .../writing-tests/parallel-execution.adoc | 3586 --------------- .../parameterized-classes-and-tests.adoc | 2624 ----------- .../pages/writing-tests/repeated-tests.adoc | 4059 +---------------- .../writing-tests/tagging-and-filtering.adoc | 3942 +--------------- .../test-classes-and-methods.adoc | 3865 ---------------- .../writing-tests/test-execution-order.adoc | 3999 +--------------- .../test-instance-lifecycle.adoc | 3876 ---------------- .../test-interfaces-and-default-methods.adoc | 3936 +--------------- .../pages/writing-tests/test-templates.adoc | 3925 ---------------- .../ROOT/pages/writing-tests/timeouts.adoc | 3778 --------------- 24 files changed, 555 insertions(+), 91175 deletions(-) diff --git a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc index 18eddfd55b43..7760a11d372a 100644 --- a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc @@ -1,20 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - [[writing-tests-annotations]] === Annotations @@ -189,3752 +172,3 @@ void myFastTest() { } ---- -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc index 18eddfd55b43..71345d429bd0 100644 --- a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc @@ -1,461 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - [[writing-tests-assertions]] === Assertions @@ -555,3386 +97,3 @@ analysis tool that fails the build if Jupiter's `Assertions` class is used. ---- ==== -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc index 18eddfd55b43..ccf7be42d671 100644 --- a/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc @@ -1,560 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - [[writing-tests-assumptions]] === Assumptions @@ -588,3353 +31,3 @@ To do so, you can statically import the `assumeThat()` method from `org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your assumptions. -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc index 18eddfd55b43..7dfa2ee9e328 100644 --- a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc @@ -1,3647 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - [[writing-tests-built-in-extensions]] === Built-in Extensions diff --git a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc index 18eddfd55b43..e6abf92bf6ba 100644 --- a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc @@ -1,2945 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - [[writing-tests-class-templates]] === Class Templates @@ -2954,987 +12,3 @@ with full support for the same lifecycle callbacks and extensions. Please refer NOTE: <> are a built-in specialization of class templates. -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc index 18eddfd55b43..068f8db579ae 100644 --- a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc @@ -1,3940 +1,224 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. +[[writing-tests-conditional-execution]] +=== Conditional Test Execution -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. +The <> extension API in JUnit Jupiter allows +developers to either _enable_ or _disable_ a test class or test method based on certain +conditions _programmatically_. The simplest example of such a condition is the built-in +`{DisabledCondition}` which supports the `{Disabled}` annotation (see +<>). -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** +In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based +conditions in the `org.junit.jupiter.api.condition` package that allow developers to +enable or disable test classes and test methods _declaratively_. If you wish to provide +details about why they might be disabled, every annotation associated with these built-in +conditions has a `disabledReason` attribute available for that purpose. -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods +When multiple `ExecutionCondition` extensions are registered, a test class or test method +is disabled as soon as one of the conditions returns _disabled_. If a test class is +disabled, all test methods within that class are automatically disabled as well. If a test +method is disabled, that prevents execution of the test method and method-level lifecycle +callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension +APIs. However, that does not prevent the test class from being instantiated, and it does +not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, +`@AfterAll` methods, and corresponding extension APIs. -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). +See <> and the following sections for +details. -[NOTE] -.Class and method visibility +[TIP] +.Composed Annotations ==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. +Note that any of the _conditional_ annotations listed in the following sections may also +be used as a meta-annotation in order to create a custom _composed annotation_. For +example, the `@TestOnMac` annotation in the +<> shows how you can +combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. ==== [NOTE] -.Field and method inheritance ==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. ==== -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. +[WARNING] +==== +Unless otherwise stated, each of the _conditional_ annotations listed in the following +sections can only be declared once on a given test interface, test class, or test method. +If a conditional annotation is directly present, indirectly present, or meta-present +multiple times on a given element, only the first such annotation discovered by JUnit will +be used; any additional declarations will be silently ignored. Note, however, that each +conditional annotation may be used in conjunction with other conditional annotations in +the `org.junit.jupiter.api.condition` package. +==== -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- +[[writing-tests-conditional-execution-os]] +==== Operating System and Architecture Conditions -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. +A container or test may be enabled or disabled on a particular operating system, +architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` +annotations. +[[writing-tests-conditional-execution-os-demo]] [source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin +.Conditional execution based on operating system ---- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ---- -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - +[[writing-tests-conditional-execution-architectures-demo]] [source,java,indent=0] +.Conditional execution based on architecture ---- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ---- -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== +[[writing-tests-conditional-execution-jre]] +==== Java Runtime Environment Conditions -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. +A container or test may be enabled or disabled on particular versions of the Java Runtime +Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a +particular range of versions of the JRE via the `{EnabledForJreRange}` and +`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the +lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. +The following listing demonstrates the use of these annotations with predefined {JRE} enum +constants. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ---- -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== +Since the enum constants defined in {JRE} are static for any given JUnit release, you +might find that you need to configure a Java version that is not supported by the `JRE` +enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` +as the highest supported Java version. However, you may wish to run your tests against +later versions of Java. To support such use cases, you can specify arbitrary Java versions +via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the +`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and +`@DisabledForJreRange`. -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. +The following listing demonstrates the use of these annotations with arbitrary Java +versions. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ---- -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== +[[writing-tests-conditional-execution-native]] +==== Native Image Conditions -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. +A container or test may be enabled or disabled within a +https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the +`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are +typically used when running tests within a native image using the Gradle and Maven +plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native +Build Tools] project. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ---- -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. +[[writing-tests-conditional-execution-system-properties]] +==== System Property Conditions -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. +A container or test may be enabled or disabled based on the value of the `named` JVM +system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` +annotations. The value supplied via the `matches` attribute will be interpreted as a +regular expression. [source,java,indent=0] ---- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ---- -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` +[TIP] ==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. +`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. +Consequently, these annotations may be declared multiple times on a test interface, test +class, or test method. Specifically, these annotations will be found if they are directly +present, indirectly present, or meta-present on a given element. ==== -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. +[[writing-tests-conditional-execution-environment-variables]] +==== Environment Variable Conditions -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. +A container or test may be enabled or disabled based on the value of the `named` +environment variable from the underlying operating system via the +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The +value supplied via the `matches` attribute will be interpreted as a regular expression. [source,java,indent=0] ---- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ---- [TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath ==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- +`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable +annotations_. Consequently, these annotations may be declared multiple times on a test +interface, test class, or test method. Specifically, these annotations will be found if +they are directly present, indirectly present, or meta-present on a given element. ==== -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. +[[writing-tests-conditional-execution-custom]] +==== Custom Conditions -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. +As an alternative to implementing an <>, a +container or test may be enabled or disabled based on a _condition method_ configured via +the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` +return type and may accept either no arguments or a single `ExtensionContext` argument. -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. +The following test class demonstrates how to configure a local method named +`customCondition` via `@EnabledIf` and `@DisabledIf`. [source,java,indent=0] ---- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ---- -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. +Alternatively, the condition method can be located outside the test class. In this case, +it must be referenced by its _fully qualified name_ as demonstrated in the following +example. -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. +[source,java,indent=0] +---- +package example; -[[writing-tests-exceptions]] -=== Exception Handling +include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +---- -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. +[NOTE] +==== +There are several cases where a condition method would need to be `static`: -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions +- when `@EnabledIf` or `@DisabledIf` is used at class level +- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a + `@TestTemplate` method +- when the condition method is located in an external class -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. +In any other case, you can use either static methods or instance methods as condition +methods. +==== [TIP] ==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. +It is often the case that you can use an existing static method in a utility class as a +custom condition. -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. +For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` +method that can be used to determine if the current environment does not support a +graphical display. Thus, if you have a test that depends on graphical support you can +disable it when such support is unavailable as follows. [source,java,indent=0] ---- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread +@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", + disabledReason = "headless environment") ---- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation ==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc index 18eddfd55b43..b572ec559b06 100644 --- a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc @@ -1,194 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - [[writing-tests-definitions]] === Definitions @@ -220,3721 +29,3 @@ With the exception of `@Test`, these create a _container_ in the test tree that _tests_ or, potentially (for `@TestFactory`), other _containers_. **** -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc index 18eddfd55b43..963d1b2f6df0 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc @@ -1,3940 +1,92 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` +[[writing-tests-dependency-injection]] +=== Dependency Injection for Constructors and Methods -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax +In all prior JUnit versions, test constructors or methods were not allowed to have +parameters (at least not with the standard `Runner` implementations). As one of the major +changes in JUnit Jupiter, both test constructors and methods are now permitted to have +parameters. This allows for greater flexibility and enables _Dependency Injection_ for +constructors and methods. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- +`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ +resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a +_lifecycle method_ (see <>) accepts a parameter, the parameter +must be resolved at runtime by a registered `ParameterResolver`. -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. +There are currently three built-in resolvers that are registered automatically. -Any method-level `@DefaultLocale` configurations will override class-level configurations. +* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type + `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` + corresponding to the current container or test as the value for the parameter. The + `TestInfo` can then be used to retrieve information about the current container or test + such as the display name, the test class, the test method, and associated tags. The + display name is either a technical name, such as the name of the test class or test + method, or a custom name configured via `@DisplayName`. ++ +`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The +following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test +class constructor, `@BeforeEach` method, and `@Test` method. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ---- -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. +* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or + `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply + an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve + information about the current repetition, the total number of repetitions, the number of + repetitions that have failed, and the failure threshold for the corresponding + `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the + context of a `@RepeatedTest`. See <>. -If your use case is not covered, you can implement the `{LocaleProvider}` interface. +* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type + `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of + `TestReporter`. The `TestReporter` can be used to publish additional data about the + current test run or attach files to it. The data can be consumed in a + `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` + method, respectively. This allows them to be viewed in IDEs or included in reports. ++ +In JUnit Jupiter you should use `TestReporter` where you used to print information to +`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display +them in the user interface for test results. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- +NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate +<> via `@ExtendWith`. -Any method level `@DefaultTimeZone` configurations will override class level configurations: +Check out the `{RandomParametersExtension}` for an example of a custom +`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the +simplicity and expressiveness of both the extension model and the parameter resolution +process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` +methods. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- +@ExtendWith(RandomParametersExtension.class) +class MyRandomParametersTest { -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. + @Test + void injectsInteger(@Random int i, @Random int j) { + assertNotEquals(i, j); + } -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. + @Test + void injectsDouble(@Random double d) { + assertEquals(0.0, d, 1.0); + } -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +} ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: +For real-world use cases, check out the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` +When the type of the parameter to inject is the only condition for your +`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. +The `supportsParameters` method is implemented behind the scenes and supports +parameterized types. -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc index 18eddfd55b43..cf8460955594 100644 --- a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc @@ -1,714 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - [[writing-tests-disabling]] === Disabling Tests @@ -757,3184 +46,3 @@ superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. ==== -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc index 18eddfd55b43..2346875b83a8 100644 --- a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc @@ -1,300 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - [[writing-tests-display-names]] === Display Names @@ -456,3485 +159,3 @@ following precedence rules: parameter, if present 4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc index 18eddfd55b43..92c3ae99ffbd 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc @@ -1,2974 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - [[writing-tests-dynamic-tests]] === Dynamic Tests @@ -3126,815 +155,3 @@ modes: **** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) ** ... (same for "Container B" and "Container C") -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc index 18eddfd55b43..23d17f93f422 100644 --- a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc @@ -1,593 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - [[writing-tests-exceptions]] === Exception Handling @@ -709,3232 +119,3 @@ NOTE: Third-party assertion libraries often provide similar support. For example has `assertThatNoException().isThrownBy(() -> ...)`. See also: <>. -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/intro.adoc b/documentation/modules/ROOT/pages/writing-tests/intro.adoc index 18eddfd55b43..1b6b9b38b953 100644 --- a/documentation/modules/ROOT/pages/writing-tests/intro.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/intro.adoc @@ -15,3926 +15,3 @@ available features. include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ---- -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc index 18eddfd55b43..9fa0ed86d4b9 100644 --- a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc @@ -1,3940 +1,73 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. +[[writing-tests-nested]] +=== Nested Tests -If your use case is not covered, you can implement the `{LocaleProvider}` interface. +`@Nested` tests give the test writer more capabilities to express the relationship among +several groups of tests. Such nested tests make use of Java's nested classes and +facilitate hierarchical thinking about the test structure. Here's an elaborate example, +both as source code and as a screenshot of the execution within an IDE. [source,java,indent=0] +.Nested test suite for testing a stack ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. +When executing this example in an IDE, the test execution tree in the GUI will look +similar to the following image. -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone +image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. +In this example, preconditions from outer tests are used in inner tests by defining +hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a +`@BeforeEach` lifecycle method that is used in the test class in which it is defined and +in all levels in the nesting tree below the class in which it is defined. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- +The fact that setup code from outer tests is run before inner tests are executed gives you +the ability to run all tests independently. You can even run inner tests alone without +running the outer tests, because the setup code from the outer tests is always executed. -Any method level `@DefaultTimeZone` configurations will override class level configurations: +NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test +classes. Nesting can be arbitrarily deep, and those inner classes are subject to full +lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- +[[writing-tests-nested-interoperability]] +==== Interoperability -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. +`@Nested` may be combined with +<> in which case the nested test +class is parameterized. -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. +The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and +`@ParameterizedTest`. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: +Executing the above test class yields the following output: -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` +.... +FruitTests ✔ +├─ [1] fruit = "apple" ✔ +│ └─ QuantityTests ✔ +│ ├─ [1] quantity = 23 ✔ +│ │ └─ test(Duration) ✔ +│ │ ├─ [1] duration = "PT1H" ✔ +│ │ └─ [2] duration = "PT2H" ✔ +│ └─ [2] quantity = 42 ✔ +│ └─ test(Duration) ✔ +│ ├─ [1] duration = "PT1H" ✔ +│ └─ [2] duration = "PT2H" ✔ +└─ [2] fruit = "banana" ✔ + └─ QuantityTests ✔ + ├─ [1] quantity = 23 ✔ + │ └─ test(Duration) ✔ + │ ├─ [1] duration = "PT1H" ✔ + │ └─ [2] duration = "PT2H" ✔ + └─ [2] quantity = 42 ✔ + └─ test(Duration) ✔ + ├─ [1] duration = "PT1H" ✔ + └─ [2] duration = "PT2H" ✔ +.... -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc index 18eddfd55b43..dba5c7e15b82 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc @@ -1,3293 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - [[writing-tests-parallel-execution]] === Parallel Execution @@ -3642,299 +352,3 @@ include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags ---- -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc index 18eddfd55b43..70484f86cf21 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc @@ -1,1629 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - [[writing-tests-parameterized-tests]] === Parameterized Classes and Tests @@ -2940,1001 +1314,3 @@ include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] <3> Validation and cleanup of the argument _after_ each invocation of the parameterized class -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc index 18eddfd55b43..c0e4eeb7544b 100644 --- a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc @@ -1,3940 +1,177 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. +[[writing-tests-repeated-tests]] +=== Repeated Tests -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. +JUnit Jupiter provides the ability to repeat a test a specified number of times by +annotating a method with `@RepeatedTest` and specifying the total number of repetitions +desired. Each invocation of a repeated test behaves like the execution of a regular +`@Test` method with full support for the same lifecycle callbacks and extensions. -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. +The following example demonstrates how to declare a test named `repeatedTest()` that +will be automatically repeated 10 times. [source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ---- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +@RepeatedTest(10) +void repeatedTest() { + // ... +} ---- -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax +`@RepeatedTest` can be configured with a failure threshold which signifies the number of +failures after which remaining repetitions will be automatically skipped. Set the +`failureThreshold` attribute to a positive number less than the total number of +repetitions in order to skip the invocations of remaining repetitions after the specified +number of failures has been encountered. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- +For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect +to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and +there is no need to invoke the remaining repetitions. To support that specific use case, +set `failureThreshold = 1`. You can alternatively set the threshold to a number greater +than 1 depending on your use case. -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. +By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that +no failure threshold will be applied, which effectively means that the specified number of +repetitions will be invoked regardless of whether any repetitions fail. -Any method-level `@DefaultLocale` configurations will override class-level configurations. +WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no +guarantees can be made regarding the failure threshold. It is therefore recommended that a +`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution +is configured. See <> for further details. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- +In addition to specifying the number of repetitions and failure threshold, a custom +display name can be configured for each repetition via the `name` attribute of the +`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a +combination of static text and dynamic placeholders. The following placeholders are +currently supported. -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. +- `+{displayName}+`: display name of the `@RepeatedTest` method +- `+{currentRepetition}+`: the current repetition count +- `+{totalRepetitions}+`: the total number of repetitions -If your use case is not covered, you can implement the `{LocaleProvider}` interface. +The default display name for a given repetition is generated based on the following +pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display +names for individual repetitions of the previous `repeatedTest()` example would be: +`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of +the `@RepeatedTest` method included in the name of each repetition, you can define your +own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The +latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of ++{totalRepetitions}+"` which results in display names for individual repetitions like +`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- +In order to retrieve information about the current repetition, the total number of +repetitions, the number of repetitions that have failed, and the failure threshold, a +developer can choose to have an instance of `{RepetitionInfo}` injected into a +`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. -NOTE: The provider implementation must have a no-args (or the default) constructor. +[[writing-tests-repeated-tests-examples]] +==== Repeated Test Examples -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone +The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of +repeated tests. -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. +The `repeatedTest()` method is identical to the example from the previous section; whereas, +`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of +`RepetitionInfo` injected into a test to access the total number of repetitions for the +current repeated test. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- +`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and +simulates an unexpected failure for every second repetition.The resulting behavior can be +viewed in the `ConsoleLauncher` output at the end of this section. -Any method level `@DefaultTimeZone` configurations will override class level configurations: +The next two methods demonstrate how to include a custom `@DisplayName` for the +`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` +combines a custom display name with a custom pattern and then uses `TestInfo` to verify +the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes +from the `@DisplayName` declaration, and `1/1` comes from +`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, +`customDisplayNameWithLongPattern()` uses the aforementioned predefined +`RepeatedTest.LONG_DISPLAY_NAME` pattern. -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- +`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated +tests into foreign languages -- in this case German, resulting in names for individual +repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. +Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed +before each repetition of each repeated test. By having the `TestInfo` and +`RepetitionInfo` injected into the method, we see that it's possible to obtain +information about the currently executing repeated test. Executing `RepeatedTestsDemo` +with the `INFO` log level enabled results in the following output. -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. +.... +INFO: About to execute repetition 1 of 10 for repeatedTest +INFO: About to execute repetition 2 of 10 for repeatedTest +INFO: About to execute repetition 3 of 10 for repeatedTest +INFO: About to execute repetition 4 of 10 for repeatedTest +INFO: About to execute repetition 5 of 10 for repeatedTest +INFO: About to execute repetition 6 of 10 for repeatedTest +INFO: About to execute repetition 7 of 10 for repeatedTest +INFO: About to execute repetition 8 of 10 for repeatedTest +INFO: About to execute repetition 9 of 10 for repeatedTest +INFO: About to execute repetition 10 of 10 for repeatedTest +INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo +INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold +INFO: About to execute repetition 1 of 1 for customDisplayName +INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern +INFO: About to execute repetition 1 of 5 for repeatedTestInGerman +INFO: About to execute repetition 2 of 5 for repeatedTestInGerman +INFO: About to execute repetition 3 of 5 for repeatedTestInGerman +INFO: About to execute repetition 4 of 5 for repeatedTestInGerman +INFO: About to execute repetition 5 of 5 for repeatedTestInGerman +.... -[source,java,indent=0] +[source,java] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. +When using the `ConsoleLauncher` with the unicode theme enabled, execution of +`RepeatedTestsDemo` results in the following output to the console. -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: +.... +├─ RepeatedTestsDemo ✔ +│ ├─ repeatedTest() ✔ +│ │ ├─ repetition 1 of 10 ✔ +│ │ ├─ repetition 2 of 10 ✔ +│ │ ├─ repetition 3 of 10 ✔ +│ │ ├─ repetition 4 of 10 ✔ +│ │ ├─ repetition 5 of 10 ✔ +│ │ ├─ repetition 6 of 10 ✔ +│ │ ├─ repetition 7 of 10 ✔ +│ │ ├─ repetition 8 of 10 ✔ +│ │ ├─ repetition 9 of 10 ✔ +│ │ └─ repetition 10 of 10 ✔ +│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 5 ✔ +│ │ ├─ repetition 2 of 5 ✔ +│ │ ├─ repetition 3 of 5 ✔ +│ │ ├─ repetition 4 of 5 ✔ +│ │ └─ repetition 5 of 5 ✔ +│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ +│ │ ├─ repetition 1 of 8 ✔ +│ │ ├─ repetition 2 of 8 ✘ Boom! +│ │ ├─ repetition 3 of 8 ✔ +│ │ ├─ repetition 4 of 8 ✘ Boom! +│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded +│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded +│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded +│ ├─ Repeat! ✔ +│ │ └─ Repeat! 1/1 ✔ +│ ├─ Details... ✔ +│ │ └─ Details... :: repetition 1 of 1 ✔ +│ └─ repeatedTestInGerman() ✔ +│ ├─ Wiederholung 1 von 5 ✔ +│ ├─ Wiederholung 2 von 5 ✔ +│ ├─ Wiederholung 3 von 5 ✔ +│ ├─ Wiederholung 4 von 5 ✔ +│ └─ Wiederholung 5 von 5 ✔ +.... -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc index 18eddfd55b43..5023e0971ea4 100644 --- a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc @@ -1,3940 +1,16 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. +[[writing-tests-tagging-and-filtering]] +=== Tagging and Filtering -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. +Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be +used to filter <>. Please refer to the +<> section for more information about tag support in the JUnit +Platform. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +include::{testDir}/example/TaggingDemo.java[tags=user_guide] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` +TIP: See <> for examples demonstrating how to create +custom annotations for tags. -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc index 18eddfd55b43..69ee0ea0a894 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc @@ -1,225 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - [[writing-tests-classes-and-methods]] === Test Classes and Methods @@ -295,3646 +73,3 @@ and https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] to be present on the classpath or module path. -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc index 18eddfd55b43..13150a3a2485 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc @@ -1,3940 +1,141 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. +[[writing-tests-test-execution-order]] +=== Test Execution Order -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. +By default, test classes and methods will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute test classes and test methods in the same order, thereby allowing for +repeatable builds. -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- +NOTE: See <> for a definition of _test method_ and _test class_. -Running the above test class results in the following display names. +[[writing-tests-test-execution-order-methods]] +==== Method Order -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== +Although true _unit tests_ typically should not rely on the order in which they are +executed, there are times when it is necessary to enforce a specific test method execution +order -- for example, when writing _integration tests_ or _functional tests_ where the +sequence of the tests is important, especially in conjunction with +`@TestInstance(Lifecycle.PER_CLASS)`. -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. +To control the order in which test methods are executed, annotate your test class or test +interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` +implementation. You can implement your own custom `MethodOrderer` or use one of the +following built-in `MethodOrderer` implementations. -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- +* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their + display names (see <>) +* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names + and formal parameter lists +* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values + specified via the `{Order}` annotation +* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports + configuration of a custom _seed_ -Running the above test class results in the following display names. +The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes +it contains, recursively. If you want to avoid that a `@Nested` test class uses the same +`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together +with `{TestMethodOrder}`. -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== +NOTE: See also: <> -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. +The following example demonstrates how to guarantee that test methods are executed in the +order specified via the `@Order` annotation. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ---- -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator +[[writing-tests-test-execution-order-methods-default]] +===== Setting the Default Method Orderer -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. +You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +`{MethodOrderer}` you would like to use by default. Just like for the orderer configured +via the `{TestMethodOrder}` annotation, the supplied class has to implement the +`MethodOrderer` interface. The default orderer will be used for all tests unless the +`@TestMethodOrder` annotation is present on an enclosing test class or test interface. -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): +For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you +should set the configuration parameter to the corresponding fully qualified class name +(e.g., in `src/test/resources/junit-platform.properties`): [source,properties,indent=0] ---- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores +junit.jupiter.testmethod.order.default = \ + org.junit.jupiter.api.MethodOrderer$OrderAnnotation ---- Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- +`MethodOrderer`. -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. +[[writing-tests-test-execution-order-classes]] +==== Class Order -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== +Although test classes typically should not rely on the order in which they are executed, +there are times when it is desirable to enforce a specific test class execution order. You +may wish to execute test classes in a random order to ensure there are no accidental +dependencies between test classes, or you may wish to order test classes to optimize build +time as outlined in the following scenarios. -[[writing-tests-assumptions]] -=== Assumptions +* Run previously failing tests and faster tests first: "fail fast" mode +* With parallel execution enabled, schedule longer tests first: "shortest test plan + execution duration" mode +* Various other use cases -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. +To configure test class execution order _globally_ for the entire test suite, use the +`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +like to use. The supplied class must implement the `ClassOrderer` interface. -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. +You can implement your own custom `ClassOrderer` or use one of the following built-in +`ClassOrderer` implementations. -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. +* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully + qualified class names +* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their + display names (see <>) +* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values + specified via the `{Order}` annotation +* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports + configuration of a custom _seed_ -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. +For example, for the `@Order` annotation to be honored on _test classes_, you should +configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration +parameter with the corresponding fully qualified class name (e.g., in +`src/test/resources/junit-platform.properties`): -[source,java,indent=0] +[source,properties,indent=0] ---- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +junit.jupiter.testclass.order.default = \ + org.junit.jupiter.api.ClassOrderer$OrderAnnotation ---- -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. +The configured `ClassOrderer` will be applied to all top-level test classes (including +`static` nested test classes) and `@Nested` test classes. -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. +NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` +test classes will be ordered relative to other `@Nested` test classes sharing the same +_enclosing class_. -See <> for further details and examples. -==== +To configure test class execution order _locally_ for `@Nested` test classes, declare the +`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you +want to order, and supply a class reference to the `ClassOrderer` implementation you would +like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` +will be applied recursively to `@Nested` test classes and their `@Nested` test classes. +If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its +enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. +Note that a local `@TestClassOrder` declaration always overrides an inherited +`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the +`junit.jupiter.testclass.order.default` configuration parameter. -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. +The following example demonstrates how to guarantee that `@Nested` test classes are +executed in the order specified via the `@Order` annotation. [source,java,indent=0] ---- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ---- -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc index 18eddfd55b43..b92bf55f492e 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc @@ -1,1143 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - [[writing-tests-test-instance-lifecycle]] === Test Instance Lifecycle @@ -1202,2739 +62,3 @@ configures "per-class" semantics as the default but tests in the IDE are execute build server. It is therefore recommended to change the default in the JUnit Platform configuration file instead of via a JVM system property. -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc index 18eddfd55b43..2a7468bcbcc3 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc @@ -1,3940 +1,80 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. +[[writing-tests-test-interfaces-and-default-methods]] +=== Test Interfaces and Default Methods -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. +JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, +`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` +methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a +test interface or on interface `default` methods _if_ the test interface or test class is +annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see +<>). Here are some examples. [source,java] ---- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ---- -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - [source,java] ---- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ---- -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. +`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that +implement the interface automatically inherit its tags and extensions. See +<> for the source code of the +<>. [source,java] ---- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ---- -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. +In your test class you can then implement these test interfaces to have them applied. [source,java] ---- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ---- -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- +Running the `TestInterfaceDemo` results in output similar to the following: -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. +.... +INFO example.TestLifecycleLogger - Before all tests +INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] +INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. +INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] +INFO example.TestLifecycleLogger - About to execute [isEqualValue()] +INFO example.TimingExtension - Method [isEqualValue] took 1 ms. +INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] +INFO example.TestLifecycleLogger - After all tests +.... -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: +Another possible application of this feature is to write tests for interface contracts. +For example, you can write tests for how implementations of `Object.equals` or +`Comparable.compareTo` should behave as follows. [source,java] ---- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread +include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ---- -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - [source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ---- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ---- [source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ---- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ---- -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. +In your test class you can then implement both contract interfaces thereby inheriting the +corresponding tests. Of course you'll have to implement the abstract methods. [source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ---- -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: +NOTE: The above tests are merely meant as examples and therefore not complete. -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc index 18eddfd55b43..9c8bc506957a 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc @@ -1,2959 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - [[writing-tests-test-templates]] === Test Templates @@ -2969,972 +13,3 @@ NOTE: <> and <> are built-in specializations of test templates. -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - -[[writing-tests-declarative-timeouts]] -=== Timeouts - -The `@Timeout` annotation allows one to declare that a test, test factory, test template, -or lifecycle method should fail if its execution time exceeds a given duration. The time -unit for the duration defaults to seconds but is configurable. - -The following example shows how `@Timeout` is applied to lifecycle and test methods. - -[source,java] ----- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] ----- - -To apply the same timeout to all test methods within a test class and all of its `@Nested` -classes, you can declare the `@Timeout` annotation at the class level. It will then be -applied to all test, test factory, and test template methods within that class and its -`@Nested` classes unless overridden by a `@Timeout` annotation on a specific method or -`@Nested` class. Please note that `@Timeout` annotations declared at the class level are -not applied to lifecycle methods. - -Declaring `@Timeout` on a `@TestFactory` method checks that the factory method returns -within the specified duration but does not verify the execution time of each individual -`DynamicTest` generated by the factory. Please use -`assertTimeout()` or `assertTimeoutPreemptively()` for that purpose. - -If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or -`@ParameterizedTest` — each invocation will have the given timeout applied to it. - -[[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode - -The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, -`SEPARATE_THREAD`, or `INFERRED`. - -When `SAME_THREAD` is used, the execution of the annotated method proceeds in the main -thread of the test. If the timeout is exceeded, the main thread is interrupted from -another thread. This is done to ensure interoperability with frameworks such as Spring -that make use of mechanisms that are sensitive to the currently running thread — for -example, `ThreadLocal` transaction management. - -On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` -assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. - -When `INFERRED` (default) thread mode is used, the thread mode is resolved via the -`junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the -provided configuration parameter is invalid or not present then `SAME_THREAD` is used as -fallback. - -[[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts - -The following <> can be used to -specify default timeouts for all methods of a certain category unless they or an enclosing -test class is annotated with `@Timeout`: - -`junit.jupiter.execution.timeout.default`:: - Default timeout for all testable and lifecycle methods -`junit.jupiter.execution.timeout.testable.method.default`:: - Default timeout for all testable methods -`junit.jupiter.execution.timeout.test.method.default`:: - Default timeout for `@Test` methods -`junit.jupiter.execution.timeout.testtemplate.method.default`:: - Default timeout for `@TestTemplate` methods -`junit.jupiter.execution.timeout.testfactory.method.default`:: - Default timeout for `@TestFactory` methods -`junit.jupiter.execution.timeout.lifecycle.method.default`:: - Default timeout for all lifecycle methods -`junit.jupiter.execution.timeout.beforeall.method.default`:: - Default timeout for `@BeforeAll` methods -`junit.jupiter.execution.timeout.beforeeach.method.default`:: - Default timeout for `@BeforeEach` methods -`junit.jupiter.execution.timeout.aftereach.method.default`:: - Default timeout for `@AfterEach` methods -`junit.jupiter.execution.timeout.afterall.method.default`:: - Default timeout for `@AfterAll` methods - -More specific configuration parameters override less specific ones. For example, -`junit.jupiter.execution.timeout.test.method.default` overrides -`junit.jupiter.execution.timeout.testable.method.default` which overrides -`junit.jupiter.execution.timeout.default`. - -The values of such configuration parameters must be in the following, case-insensitive -format: ` [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be -omitted. Specifying no unit is equivalent to using seconds. - -.Example timeout configuration parameter values -[cols="20,80"] -|=== -| Parameter value | Equivalent annotation - -| `42` | `@Timeout(42)` -| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)` -| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)` -| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)` -| `42 s` | `@Timeout(value = 42, unit = SECONDS)` -| `42 m` | `@Timeout(value = 42, unit = MINUTES)` -| `42 h` | `@Timeout(value = 42, unit = HOURS)` -| `42 d` | `@Timeout(value = 42, unit = DAYS)` -|=== - - -[[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests - -When dealing with asynchronous code, it is common to write tests that poll while waiting -for something to happen before performing any assertions. In some cases you can rewrite -the logic to use a `CountDownLatch` or another synchronization mechanism, but sometimes -that is not possible — for example, if the subject under test sends a message to a channel -in an external message broker and assertions cannot be performed until the message has -been successfully sent through the channel. Asynchronous tests like these require some -form of timeout to ensure they don't hang the test suite by executing indefinitely, as -would be the case if an asynchronous message never gets successfully delivered. - -By configuring a timeout for an asynchronous test that polls, you can ensure that the test -does not execute indefinitely. The following example demonstrates how to achieve this with -JUnit Jupiter's `@Timeout` annotation. This technique can be used to implement "poll -until" logic very easily. - -[source,java] ----- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ----- - -NOTE: If you need more control over polling intervals and greater flexibility with -asynchronous tests, consider using a dedicated library such as -link:https://github.com/awaitility/awaitility[Awaitility]. - - -[[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts - -Registered <> extensions are called prior to invoking -`Thread.interrupt()` on the thread that is executing the timed out method. This allows to -inspect the application state and output additional information that might be helpful for -diagnosing the cause of a timeout. - - -[[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout - -JUnit registers a default implementation of the <> -extension point that dumps the stacks of all threads to `System.out` if enabled by setting -the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. - - -[[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally - -When stepping through your code in a debug session, a fixed timeout limit may influence -the result of the test, e.g. mark the test as failed although all assertions were met. - -JUnit Jupiter supports the `junit.jupiter.execution.timeout.mode` configuration parameter -to configure when timeouts are applied. There are three modes: `enabled`, `disabled`, -and `disabled_on_debug`. The default mode is `enabled`. -A VM runtime is considered to run in debug mode when one of its input parameters starts -with `-agentlib:jdwp` or `-Xrunjdwp`. -This heuristic is queried by the `disabled_on_debug` mode. - - -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. diff --git a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc index 18eddfd55b43..2cabb0284124 100644 --- a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc @@ -1,3131 +1,3 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests - -The following example provides a glimpse at the minimum requirements for writing a test in -JUnit Jupiter. Subsequent sections of this chapter will provide further details on all -available features. - -[source,java,indent=0] -.A first test case ----- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ----- - -[[writing-tests-annotations]] -=== Annotations - -JUnit Jupiter supports the following annotations for configuring tests and extending the -framework. - -Unless otherwise stated, all core annotations are located in the `{api-package}` package -in the `junit-jupiter-api` module. - -`*@Test*`:: Denotes that a method is a test method. Unlike JUnit 4's `@Test` annotation, -this annotation does not declare any attributes, since test extensions in JUnit Jupiter -operate based on their own dedicated annotations. Such methods are inherited unless they -are overridden. - -`*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited -unless they are overridden. - -`*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they -are overridden. - -`*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are -overridden. - -`*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple -times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are -overridden. - -`*@TestClassOrder*`:: Used to configure the -<> for `@Nested` -test classes in the annotated test class. Such annotations are inherited. - -`*@TestMethodOrder*`:: Used to configure the -<> for the -annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are -inherited. - -`*@TestInstance*`:: Used to configure the -<> for the annotated test -class. Such annotations are inherited. - -`*@DisplayName*`:: Declares a custom <> for the -test class or test method. Such annotations are not inherited. - -`*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such -annotations are inherited. - -`*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@Before`. Such methods are inherited unless they are -overridden. - -`*@AfterEach*`:: Denotes that the annotated method should be executed _after_ *each* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, or `@TestFactory` method in the current -class; analogous to JUnit 4's `@After`. Such methods are inherited unless they are -overridden. - -`*@BeforeAll*`:: Denotes that the annotated method should be executed _before_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current -top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are -inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. - -`*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are -inherited. - -`*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _before_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be -executed once _after_ each invocation of a -<>. Such methods are inherited -unless they are overridden. - -`*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed -multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. - -`*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. - -`*@Tag*`:: Used to declare -<>, either at the class or -method level; analogous to test groups in TestNG or Categories in JUnit 4. Such -annotations are inherited at the class level but not at the method level. - -`*@Disabled*`:: Used to <> a test class or test method; -analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. - -`*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test -execution. Such fields are inherited. - -`*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if -its execution exceeds a given duration. Such annotations are inherited. - -`*@TempDir*`:: Used to supply a -<> via field -injection or parameter injection in a test class constructor, lifecycle method, or test -method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. - -`*@ExtendWith*`:: Used to -<>. Such -annotations are inherited. - -`*@RegisterExtension*`:: Used to -<> via fields. -Such fields are inherited. - -WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. - -[[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations - -JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can -define your own _composed annotation_ that will automatically _inherit_ the semantics of -its meta-annotations. - -For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ -named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for -`@Tag("fast")`. - -[source,java,indent=0] ----- -include::{testDir}/example/Fast.java[tags=user_guide] ----- - -The following `@Test` method demonstrates usage of the `@Fast` annotation. - -[source,java,indent=0] ----- -@Fast -@Test -void myFastTest() { - // ... -} ----- - -You can even take that one step further by introducing a custom `@FastTest` annotation -that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. - -[source,java,indent=0] ----- -include::{testDir}/example/FastTest.java[tags=user_guide] ----- - -JUnit automatically recognizes the following as a `@Test` method that is tagged with -"fast". - -[source,java,indent=0] ----- -@FastTest -void myFastTest() { - // ... -} ----- - -[[writing-tests-definitions]] -=== Definitions - -.Platform Concepts -**** -Container:: -a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). - -Test:: -a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** - -.Jupiter Concepts -**** -Lifecycle Method:: -any method that is directly annotated or meta-annotated with -`@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. - -Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. -Test classes must not be `abstract` and must have a single constructor. -Java `record` classes are supported as well. - -Test Method:: -any instance method that is directly annotated or meta-annotated with -`@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. -With the exception of `@Test`, these create a _container_ in the test tree that groups -_tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods - -Test methods and lifecycle methods may be declared locally within the current test class, -inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and -lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` -methods which are required to return a value). - -[NOTE] -.Class and method visibility -==== -Test classes, test methods, and lifecycle methods are not required to be `public`, but -they must _not_ be `private`. - -It is generally recommended to omit the `public` modifier for test classes, test methods, -and lifecycle methods unless there is a technical reason for doing so – for example, when -a test class is extended by a test class in another package. Another technical reason for -making classes and methods `public` is to simplify testing on the module path when using -the Java Module System. -==== - -[NOTE] -.Field and method inheritance -==== -Fields in test classes are inherited. For example, a `@TempDir` field from a superclass -will always be applied in a subclass. - -Test methods and lifecycle methods are inherited unless they are overridden according to -the visibility rules of the Java language. For example, a `@Test` method from a superclass -will always be applied in a subclass unless the subclass explicitly overrides the method. -Similarly, if a package-private `@Test` method is declared in a superclass that resides in -a different package than the subclass, that `@Test` method will always be applied in the -subclass since the subclass cannot override a package-private method from a superclass in -a different package. - -See also: <> -==== - -The following test class demonstrates the use of `@Test` methods and all supported -lifecycle methods. For further information on runtime semantics, see -<> and -<>. - -[source,java,indent=0] -.A standard Java test class ----- -include::{testDir}/example/StandardTests.java[tags=user_guide] ----- - -It is also possible to use Java `record` classes as test classes as illustrated by the -following example. - -[source,java,indent=0] -.A test class written as a Java record ----- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ----- - -Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` -keyword for testing code using coroutines. - -[source,kotlin] -.A test class written in Kotlin ----- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] ----- - -NOTE: Using suspending functions as test or lifecycle methods requires -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-stdlib[`kotlin-stdlib`], -https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotlin-reflect`], -and -https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] -to be present on the classpath or module path. - -[[writing-tests-display-names]] -=== Display Names - -Test classes and test methods can declare custom display names via `@DisplayName` -- with -spaces, special characters, and even emojis -- that will be displayed in test reports and -by test runners and IDEs. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] ----- - -[NOTE] -==== -Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> -for details. - -Any remaining ISO control characters in a display name will be replaced as follows. - -[cols="25%,15%,60%"] -|=== -| Original | Replacement | Description - -| ```\r``` -| `````` -| Textual representation of a carriage return - -| ```\n``` -| `````` -| Textual representation of a line feed - -| Other control character -| ```�``` -| Unicode replacement character (U+FFFD) -|=== -==== - -[[writing-tests-display-name-generator]] -==== Display Name Generators - -JUnit Jupiter supports custom display name generators that can be configured via the -`@DisplayNameGeneration` annotation. - -Generators can be created by implementing the `DisplayNameGenerator` API. The following -table lists the default display name generators available in Jupiter. - -[cols="20,80"] -|=== -| DisplayNameGenerator | Behavior - -| `Standard` | Matches the standard display name generation behavior in place since JUnit Jupiter was introduced. -| `Simple` | Extends the functionality of `Standard` by removing trailing parentheses for methods with no parameters. -| `ReplaceUnderscores` | Replaces underscores with spaces. -| `IndicativeSentences` | Generates complete sentences by concatenating the names of the test and the enclosing classes. -|=== - -NOTE: Values provided via `@DisplayName` annotations always take precedence over display -names generated by a `DisplayNameGenerator`. - -====== -The following example demonstrates the use of the `ReplaceUnderscores` display name -generator. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ----- - -Running the above test class results in the following display names. - -``` -A year is not supported ✔ -├─ if it is zero ✔ -└─ A negative value for year is not supported by the leap year computation. ✔ - ├─ For example, year -1 is not supported. ✔ - └─ For example, year -4 is not supported. ✔ -``` -====== - -====== -With the `IndicativeSentences` display name generator, you can customize the separator and -the underlying generator by using `@IndicativeSentencesGeneration` as shown in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year -> if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year -> if it is one of the following years ✔ - ├─ Year 2016 is a leap year. ✔ - ├─ Year 2020 is a leap year. ✔ - └─ Year 2048 is a leap year. ✔ -``` -====== - -====== -With `IndicativeSentences`, you can optionally specify custom sentence fragments via the -`@SentenceFragment` annotation as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ----- - -Running the above test class results in the following display names. - -``` -A year is a leap year ✔ -├─ A year is a leap year, if it is divisible by 4 but not by 100 ✔ -└─ A year is a leap year, if it is one of the following years ✔ - ├─ 2016 ✔ - ├─ 2020 ✔ - └─ 2048 ✔ -``` -====== - - -[[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator - -You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified -class name of the `DisplayNameGenerator` you would like to use by default. Just like for -display name generators configured via the `@DisplayNameGeneration` annotation, the -supplied class has to implement the `DisplayNameGenerator` interface. The default display -name generator will be used for all tests unless the `@DisplayNameGeneration` annotation -is present on an enclosing test class or test interface. Values provided via -`@DisplayName` annotations always take precedence over display names generated by a -`DisplayNameGenerator`. - -For example, to use the `ReplaceUnderscores` display name generator by default, you should -set the configuration parameter to the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.displayname.generator.default = \ - org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`DisplayNameGenerator`. - -[[writing-tests-display-name-generator-precedence-rules]] -In summary, the display name for a test class or method is determined according to the -following precedence rules: - -1. value of the `@DisplayName` annotation, if present -2. by calling the `DisplayNameGenerator` specified in the `@DisplayNameGeneration` - annotation, if present -3. by calling the default `DisplayNameGenerator` configured via the configuration - parameter, if present -4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - -[[writing-tests-assertions]] -=== Assertions - -JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few -that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions -are `static` methods in the `{Assertions}` class. - -Assertion methods optionally accept the assertion message as their third parameter, which -can be either a `String` or a `Supplier`. - -When using a `Supplier` (e.g., a lambda expression), the message is evaluated -lazily. This can provide a performance benefit, especially if message construction is -complex or time-consuming, as it is only evaluated when the assertion fails. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] ----- - -[[writing-tests-assertions-preemptive-timeouts]] -[WARNING] -.Preemptive Timeouts with `assertTimeoutPreemptively()` -==== -The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute -the provided `executable` or `supplier` in a different thread than that of the calling -code. This behavior can lead to undesirable side effects if the code that is executed -within the `executable` or `supplier` relies on `java.lang.ThreadLocal` storage. - -One common example of this is the transactional testing support in the Spring Framework. -Specifically, Spring's testing support binds transaction state to the current thread (via -a `ThreadLocal`) before a test method is invoked. Consequently, if an `executable` or -`supplier` provided to `assertTimeoutPreemptively()` invokes Spring-managed components -that participate in transactions, any actions taken by those components will not be rolled -back with the test-managed transaction. On the contrary, such actions will be committed to -the persistent store (e.g., relational database) even though the test-managed transaction -is rolled back. - -Similar side effects may be encountered with other frameworks that rely on -`ThreadLocal` storage. -==== - -[[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support - -JUnit Jupiter also comes with a few assertion methods that lend themselves well to being -used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level -functions in the `org.junit.jupiter.api` package. - -[source,kotlin,indent=0] ----- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] ----- - -[[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries - -Even though the assertion facilities provided by JUnit Jupiter are sufficient for many -testing scenarios, there are times when more power and additional functionality are -desired or required. In such cases, the JUnit team recommends the use of third-party -assertion libraries such as {AssertJ}, {Hamcrest}, {Truth}, etc. Developers are therefore -free to use the assertion library of their choice. - -For example, the following demonstrates how to use the `assertThat()` support from AssertJ -in a JUnit Jupiter test. As long as the AssertJ library has been added to the classpath, -you can statically import methods such as `assertThat()`, `assertThatException()`, etc. -from `org.assertj.core.api.Assertions` and then use them in tests like in the -`assertWithAssertJ()` method below. - -[source,java,indent=0] ----- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] ----- - -[TIP] -.Excluding Jupiter’s Assertions From a Project’s Classpath -==== -If you would like to enforce that all your tests use a certain third-party assertion -library instead of Jupiter's, you can set up a rule using {Checkstyle} or another static -analysis tool that fails the build if Jupiter's `Assertions` class is used. - -[source,xml] ----- - - - - - - - - - - - - - - ----- -==== - -[[writing-tests-assumptions]] -=== Assumptions - -Assumptions are typically used whenever it does not make sense to continue execution of a -given test — for example, if the test depends on something that does not exist in the -current runtime environment. - -* When an assumption is valid, the assumption method does not throw an exception, and - execution of the test continues as usual. -* When an assumption is invalid, the assumption method throws an exception of type - `org.opentest4j.TestAbortedException` to signal that the test should be aborted instead - of marked as a failure. - -JUnit Jupiter comes with a subset of the _assumption_ methods that JUnit 4 provides and -adds a few that lend themselves well to being used with Java lambda expressions and method -references. - -All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. - -[source,java,indent=0] ----- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] ----- - -NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for -assumptions. Specifically, JUnit Jupiter supports JUnit 4's `AssumptionViolatedException` -to signal that a test should be aborted instead of marked as a failure. - -TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for assumptions. -To do so, you can statically import the `assumeThat()` method from -`org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your -assumptions. - -[[writing-tests-exceptions]] -=== Exception Handling - -JUnit Jupiter provides robust support for handling test exceptions. This includes the -built-in mechanisms for managing test failures due to exceptions, the role of exceptions -in implementing assertions and assumptions, and how to specifically assert non-throwing -conditions in code. - -[[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions - -In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an -extension and not caught within that test method, lifecycle method, or extension, the -framework will mark the test or test class as failed. - -[TIP] -==== -Failed assumptions deviate from this general rule. - -In contrast to failed assertions, failed assumptions do not result in a test failure; -rather, a failed assumption results in a test being aborted. - -See <> for further details and examples. -==== - -In the following example, the `failsDueToUncaughtException()` method throws an -`ArithmeticException`. Since the exception is not caught within the test method, JUnit -Jupiter will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ----- - -NOTE: It's important to note that specifying a `throws` clause in the test method has -no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws` clause -as an expectation or assertion about what exceptions the test method should throw. A test -fails only if an exception is thrown unexpectedly or if an assertion fails. - -[[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions - -Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set -of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw -`AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for -further information about JUnit Jupiter's assertion support. - -NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a -failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. - -TIP: JUnit Jupiter itself does not differentiate between failed assertions -(`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test -failure. However, Integrated Development Environments (IDEs) and other tools may -distinguish between these two types of failures by checking whether the thrown exception -is an instance of `AssertionError`. - -In the following example, the `failsDueToUncaughtAssertionError()` method throws an -`AssertionError`. Since the exception is not caught within the test method, JUnit Jupiter -will mark the test as failed. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions - -JUnit Jupiter offers specialized assertions for testing that specific exceptions are -thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` -assertions are critical tools for validating that your code responds correctly to error -conditions by throwing the appropriate exceptions. - -[[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` - -The `assertThrows()` method is used to verify that a particular type of exception is -thrown during the execution of a provided executable block. It not only checks for the -type of the thrown exception but also its subclasses, making it suitable for more -generalized exception handling tests. The `assertThrows()` assertion method returns the -thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` - -The `assertThrowsExactly()` method is used when you need to assert that the exception -thrown is exactly of a specific type, not allowing for subclasses of the expected -exception type. This is useful when precise exception handling behavior needs to be -validated. Similar to `assertThrows()`, the `assertThrowsExactly()` assertion method also -returns the thrown exception object to allow performing additional assertions on it. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ----- - -[[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected - -Although any exception thrown from a test method will cause the test to fail, there are -certain use cases where it can be beneficial to explicitly assert that an exception is -_not_ thrown for a given code block within a test method. The `assertDoesNotThrow()` -assertion can be used when you want to verify that a particular piece of code does not -throw any exceptions. - -[source,java,indent=0] ----- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ----- - -NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ -has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. - -[[writing-tests-disabling]] -=== Disabling Tests - -Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` -annotation, via one of the annotations discussed in -<>, or via a custom <>. - -When `@Disabled` is applied at the class level, all test methods within that class are -automatically disabled as well. - -If a test method is disabled via `@Disabled`, that prevents execution of the test method -and method-level lifecycle callbacks such as `@BeforeEach` methods, `@AfterEach` methods, -and corresponding extension APIs. However, that does not prevent the test class from being -instantiated, and it does not prevent the execution of class-level lifecycle callbacks -such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. - -Here's a `@Disabled` test class. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] ----- - -And here's a test class that contains a `@Disabled` test method. - -[source,java,indent=0] ----- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ----- - -[TIP] -==== -`@Disabled` may be declared without providing a _reason_; however, the JUnit team -recommends that developers provide a short explanation for why a test class or test -method has been disabled. Consequently, the above examples both show the use of a reason --- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development -teams even require the presence of issue tracking numbers in the _reason_ for automated -traceability, etc. -==== - -[NOTE] -==== -`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose -superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. -==== - - -[[writing-tests-conditional-execution]] -=== Conditional Test Execution - -The <> extension API in JUnit Jupiter allows -developers to either _enable_ or _disable_ a test class or test method based on certain -conditions _programmatically_. The simplest example of such a condition is the built-in -`{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). - -In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based -conditions in the `org.junit.jupiter.api.condition` package that allow developers to -enable or disable test classes and test methods _declaratively_. If you wish to provide -details about why they might be disabled, every annotation associated with these built-in -conditions has a `disabledReason` attribute available for that purpose. - -When multiple `ExecutionCondition` extensions are registered, a test class or test method -is disabled as soon as one of the conditions returns _disabled_. If a test class is -disabled, all test methods within that class are automatically disabled as well. If a test -method is disabled, that prevents execution of the test method and method-level lifecycle -callbacks such as `@BeforeEach` methods, `@AfterEach` methods, and corresponding extension -APIs. However, that does not prevent the test class from being instantiated, and it does -not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, -`@AfterAll` methods, and corresponding extension APIs. - -See <> and the following sections for -details. - -[TIP] -.Composed Annotations -==== -Note that any of the _conditional_ annotations listed in the following sections may also -be used as a meta-annotation in order to create a custom _composed annotation_. For -example, the `@TestOnMac` annotation in the -<> shows how you can -combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. -==== - -[NOTE] -==== -_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish -to apply the same semantics to subclasses, each conditional annotation must be redeclared -on each subclass. -==== - -[WARNING] -==== -Unless otherwise stated, each of the _conditional_ annotations listed in the following -sections can only be declared once on a given test interface, test class, or test method. -If a conditional annotation is directly present, indirectly present, or meta-present -multiple times on a given element, only the first such annotation discovered by JUnit will -be used; any additional declarations will be silently ignored. Note, however, that each -conditional annotation may be used in conjunction with other conditional annotations in -the `org.junit.jupiter.api.condition` package. -==== - -[[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions - -A container or test may be enabled or disabled on a particular operating system, -architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` -annotations. - -[[writing-tests-conditional-execution-os-demo]] -[source,java,indent=0] -.Conditional execution based on operating system ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ----- - -[[writing-tests-conditional-execution-architectures-demo]] -[source,java,indent=0] -.Conditional execution based on architecture ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ----- - -[[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions - -A container or test may be enabled or disabled on particular versions of the Java Runtime -Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a -particular range of versions of the JRE via the `{EnabledForJreRange}` and -`{DisabledForJreRange}` annotations. The range effectively defaults to `JRE.JAVA_8` as the -lower bound and `JRE.OTHER` as the upper bound, which allows usage of half open ranges. - -The following listing demonstrates the use of these annotations with predefined {JRE} enum -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ----- - -Since the enum constants defined in {JRE} are static for any given JUnit release, you -might find that you need to configure a Java version that is not supported by the `JRE` -enum. For example, when JUnit Jupiter 5.12 was released the `JRE` enum defined `JAVA_25` -as the highest supported Java version. However, you may wish to run your tests against -later versions of Java. To support such use cases, you can specify arbitrary Java versions -via the `versions` attributes in `@EnabledOnJre` and `@DisabledOnJre` and via the -`minVersion` and `maxVersion` attributes in `@EnabledForJreRange` and -`@DisabledForJreRange`. - -The following listing demonstrates the use of these annotations with arbitrary Java -versions. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ----- - -[[writing-tests-conditional-execution-native]] -==== Native Image Conditions - -A container or test may be enabled or disabled within a -https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the -`{EnabledInNativeImage}` and `{DisabledInNativeImage}` annotations. These annotations are -typically used when running tests within a native image using the Gradle and Maven -plug-ins from the GraalVM https://graalvm.github.io/native-build-tools/latest/[Native -Build Tools] project. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ----- - -[[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions - -A container or test may be enabled or disabled based on the value of the `named` JVM -system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` -annotations. The value supplied via the `matches` attribute will be interpreted as a -regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ----- - -[TIP] -==== -`{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` are _repeatable annotations_. -Consequently, these annotations may be declared multiple times on a test interface, test -class, or test method. Specifically, these annotations will be found if they are directly -present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions - -A container or test may be enabled or disabled based on the value of the `named` -environment variable from the underlying operating system via the -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` annotations. The -value supplied via the `matches` attribute will be interpreted as a regular expression. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ----- - -[TIP] -==== -`{EnabledIfEnvironmentVariable}` and `{DisabledIfEnvironmentVariable}` are _repeatable -annotations_. Consequently, these annotations may be declared multiple times on a test -interface, test class, or test method. Specifically, these annotations will be found if -they are directly present, indirectly present, or meta-present on a given element. -==== - -[[writing-tests-conditional-execution-custom]] -==== Custom Conditions - -As an alternative to implementing an <>, a -container or test may be enabled or disabled based on a _condition method_ configured via -the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` -return type and may accept either no arguments or a single `ExtensionContext` argument. - -The following test class demonstrates how to configure a local method named -`customCondition` via `@EnabledIf` and `@DisabledIf`. - -[source,java,indent=0] ----- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ----- - -Alternatively, the condition method can be located outside the test class. In this case, -it must be referenced by its _fully qualified name_ as demonstrated in the following -example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ----- - -[NOTE] -==== -There are several cases where a condition method would need to be `static`: - -- when `@EnabledIf` or `@DisabledIf` is used at class level -- when `@EnabledIf` or `@DisabledIf` is used on a `@ParameterizedTest` or a - `@TestTemplate` method -- when the condition method is located in an external class - -In any other case, you can use either static methods or instance methods as condition -methods. -==== - -[TIP] -==== -It is often the case that you can use an existing static method in a utility class as a -custom condition. - -For example, `java.awt.GraphicsEnvironment` provides a `public static boolean isHeadless()` -method that can be used to determine if the current environment does not support a -graphical display. Thus, if you have a test that depends on graphical support you can -disable it when such support is unavailable as follows. - -[source,java,indent=0] ----- -@DisabledIf(value = "java.awt.GraphicsEnvironment#isHeadless", - disabledReason = "headless environment") ----- -==== - -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering - -Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit -Platform. - -[source,java,indent=0] ----- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] ----- - -TIP: See <> for examples demonstrating how to create -custom annotations for tags. - -[[writing-tests-test-execution-order]] -=== Test Execution Order - -By default, test classes and methods will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute test classes and test methods in the same order, thereby allowing for -repeatable builds. - -NOTE: See <> for a definition of _test method_ and _test class_. - -[[writing-tests-test-execution-order-methods]] -==== Method Order - -Although true _unit tests_ typically should not rely on the order in which they are -executed, there are times when it is necessary to enforce a specific test method execution -order -- for example, when writing _integration tests_ or _functional tests_ where the -sequence of the tests is important, especially in conjunction with -`@TestInstance(Lifecycle.PER_CLASS)`. - -To control the order in which test methods are executed, annotate your test class or test -interface with `{TestMethodOrder}` and specify the desired `{MethodOrderer}` -implementation. You can implement your own custom `MethodOrderer` or use one of the -following built-in `MethodOrderer` implementations. - -* `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) -* `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names - and formal parameter lists -* `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values - specified via the `{Order}` annotation -* `{MethodOrderer_Random}`: orders test methods _pseudo-randomly_ and supports - configuration of a custom _seed_ - -The `MethodOrderer` configured on a test class is inherited by the `@Nested` test classes -it contains, recursively. If you want to avoid that a `@Nested` test class uses the same -`MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together -with `{TestMethodOrder}`. - -NOTE: See also: <> - -The following example demonstrates how to guarantee that test methods are executed in the -order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer - -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the -`{MethodOrderer}` you would like to use by default. Just like for the orderer configured -via the `{TestMethodOrder}` annotation, the supplied class has to implement the -`MethodOrderer` interface. The default orderer will be used for all tests unless the -`@TestMethodOrder` annotation is present on an enclosing test class or test interface. - -For example, to use the `{MethodOrderer_OrderAnnotation}` method orderer by default, you -should set the configuration parameter to the corresponding fully qualified class name -(e.g., in `src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testmethod.order.default = \ - org.junit.jupiter.api.MethodOrderer$OrderAnnotation ----- - -Similarly, you can specify the fully qualified name of any custom class that implements -`MethodOrderer`. - -[[writing-tests-test-execution-order-classes]] -==== Class Order - -Although test classes typically should not rely on the order in which they are executed, -there are times when it is desirable to enforce a specific test class execution order. You -may wish to execute test classes in a random order to ensure there are no accidental -dependencies between test classes, or you may wish to order test classes to optimize build -time as outlined in the following scenarios. - -* Run previously failing tests and faster tests first: "fail fast" mode -* With parallel execution enabled, schedule longer tests first: "shortest test plan - execution duration" mode -* Various other use cases - -To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would -like to use. The supplied class must implement the `ClassOrderer` interface. - -You can implement your own custom `ClassOrderer` or use one of the following built-in -`ClassOrderer` implementations. - -* `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully - qualified class names -* `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) -* `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values - specified via the `{Order}` annotation -* `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports - configuration of a custom _seed_ - -For example, for the `@Order` annotation to be honored on _test classes_, you should -configure the `{ClassOrderer_OrderAnnotation}` class orderer using the configuration -parameter with the corresponding fully qualified class name (e.g., in -`src/test/resources/junit-platform.properties`): - -[source,properties,indent=0] ----- -junit.jupiter.testclass.order.default = \ - org.junit.jupiter.api.ClassOrderer$OrderAnnotation ----- - -The configured `ClassOrderer` will be applied to all top-level test classes (including -`static` nested test classes) and `@Nested` test classes. - -NOTE: Top-level test classes will be ordered relative to each other; whereas, `@Nested` -test classes will be ordered relative to other `@Nested` test classes sharing the same -_enclosing class_. - -To configure test class execution order _locally_ for `@Nested` test classes, declare the -`{TestClassOrder}` annotation on the enclosing class for the `@Nested` test classes you -want to order, and supply a class reference to the `ClassOrderer` implementation you would -like to use directly in the `@TestClassOrder` annotation. The configured `ClassOrderer` -will be applied recursively to `@Nested` test classes and their `@Nested` test classes. -If you want to avoid that a `@Nested` test class uses the same `ClassOrderer` as its -enclosing class, you can specify `{ClassOrderer_Default}` together with `@TestClassOrder`. -Note that a local `@TestClassOrder` declaration always overrides an inherited -`@TestClassOrder` declaration or a `ClassOrderer` configured globally via the -`junit.jupiter.testclass.order.default` configuration parameter. - -The following example demonstrates how to guarantee that `@Nested` test classes are -executed in the order specified via the `@Order` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ----- - -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle - -In order to allow individual test methods to be executed in isolation and to avoid -unexpected side effects due to mutable test instance state, JUnit creates a new instance -of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default -behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. - -NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, -`@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. - -If you would prefer that JUnit Jupiter execute all test methods on the same test -instance, annotate your test class with `@TestInstance(Lifecycle.PER_CLASS)`. When using -this mode, a new test instance will be created once per test class. Thus, if your test -methods rely on state stored in instance variables, you may need to reset that state in -`@BeforeEach` or `@AfterEach` methods. - -The "per-class" mode has some additional benefits over the default "per-method" mode. -Specifically, with the "per-class" mode it becomes possible to declare `@BeforeAll` and -`@AfterAll` on non-static methods as well as on interface `default` methods. - -If you are authoring tests using the Kotlin programming language, you may also find it -easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as well as -`@MethodSource` factory methods by switching to the "per-class" test instance lifecycle -mode. - -[[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle - -If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter -will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; -however, it is possible to change the _default_ for the execution of an entire test plan. -To change the default test instance lifecycle mode, set the -`junit.jupiter.testinstance.lifecycle.default` _configuration parameter_ to the name of -an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied -as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, -you can start your JVM with the following system property. - -`-Djunit.jupiter.testinstance.lifecycle.default=per_class` - -Note, however, that setting the default test instance lifecycle mode via the JUnit -Platform configuration file is a more robust solution since the configuration file can be -checked into a version control system along with your project and can therefore be used -within IDEs and your build software. - -To set the default test instance lifecycle mode to `Lifecycle.PER_CLASS` via the JUnit -Platform configuration file, create a file named `junit-platform.properties` in the root -of the class path (e.g., `src/test/resources`) with the following content. - -`junit.jupiter.testinstance.lifecycle.default = per_class` - -WARNING: Changing the _default_ test instance lifecycle mode can lead to unpredictable -results and fragile builds if not applied consistently. For example, if the build -configures "per-class" semantics as the default but tests in the IDE are executed using -"per-method" semantics, that can make it difficult to debug errors that occur on the -build server. It is therefore recommended to change the default in the JUnit Platform -configuration file instead of via a JVM system property. - -[[writing-tests-nested]] -=== Nested Tests - -`@Nested` tests give the test writer more capabilities to express the relationship among -several groups of tests. Such nested tests make use of Java's nested classes and -facilitate hierarchical thinking about the test structure. Here's an elaborate example, -both as source code and as a screenshot of the execution within an IDE. - -[source,java,indent=0] -.Nested test suite for testing a stack ----- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] ----- - -When executing this example in an IDE, the test execution tree in the GUI will look -similar to the following image. - -image::writing-tests_nested_test_ide.png[caption='',title='Executing a nested test in an IDE'] - -In this example, preconditions from outer tests are used in inner tests by defining -hierarchical lifecycle methods for the setup code. For example, `createNewStack()` is a -`@BeforeEach` lifecycle method that is used in the test class in which it is defined and -in all levels in the nesting tree below the class in which it is defined. - -The fact that setup code from outer tests is run before inner tests are executed gives you -the ability to run all tests independently. You can even run inner tests alone without -running the outer tests, because the setup code from the outer tests is always executed. - -NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nested` test -classes. Nesting can be arbitrarily deep, and those inner classes are subject to full -lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. - -[[writing-tests-nested-interoperability]] -==== Interoperability - -`@Nested` may be combined with -<> in which case the nested test -class is parameterized. - -The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and -`@ParameterizedTest`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] ----- - -Executing the above test class yields the following output: - -.... -FruitTests ✔ -├─ [1] fruit = "apple" ✔ -│ └─ QuantityTests ✔ -│ ├─ [1] quantity = 23 ✔ -│ │ └─ test(Duration) ✔ -│ │ ├─ [1] duration = "PT1H" ✔ -│ │ └─ [2] duration = "PT2H" ✔ -│ └─ [2] quantity = 42 ✔ -│ └─ test(Duration) ✔ -│ ├─ [1] duration = "PT1H" ✔ -│ └─ [2] duration = "PT2H" ✔ -└─ [2] fruit = "banana" ✔ - └─ QuantityTests ✔ - ├─ [1] quantity = 23 ✔ - │ └─ test(Duration) ✔ - │ ├─ [1] duration = "PT1H" ✔ - │ └─ [2] duration = "PT2H" ✔ - └─ [2] quantity = 42 ✔ - └─ test(Duration) ✔ - ├─ [1] duration = "PT1H" ✔ - └─ [2] duration = "PT2H" ✔ -.... - -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods - -In all prior JUnit versions, test constructors or methods were not allowed to have -parameters (at least not with the standard `Runner` implementations). As one of the major -changes in JUnit Jupiter, both test constructors and methods are now permitted to have -parameters. This allows for greater flexibility and enables _Dependency Injection_ for -constructors and methods. - -`{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ -resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter -must be resolved at runtime by a registered `ParameterResolver`. - -There are currently three built-in resolvers that are registered automatically. - -* `{TestInfoParameterResolver}`: if a constructor or method parameter is of type - `{TestInfo}`, the `TestInfoParameterResolver` will supply an instance of `TestInfo` - corresponding to the current container or test as the value for the parameter. The - `TestInfo` can then be used to retrieve information about the current container or test - such as the display name, the test class, the test method, and associated tags. The - display name is either a technical name, such as the name of the test class or test - method, or a custom name configured via `@DisplayName`. -+ -`{TestInfo}` acts as a drop-in replacement for the `TestName` rule from JUnit 4. The -following demonstrates how to have `TestInfo` injected into a `@BeforeAll` method, test -class constructor, `@BeforeEach` method, and `@Test` method. - -[source,java,indent=0] ----- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] ----- - -* `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or - `@AfterEach` method is of type `{RepetitionInfo}`, the `RepetitionExtension` will supply - an instance of `RepetitionInfo`. `RepetitionInfo` can then be used to retrieve - information about the current repetition, the total number of repetitions, the number of - repetitions that have failed, and the failure threshold for the corresponding - `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. - -* `{TestReporterParameterResolver}`: if a constructor or method parameter is of type - `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of - `TestReporter`. The `TestReporter` can be used to publish additional data about the - current test run or attach files to it. The data can be consumed in a - `{TestExecutionListener}` via the `reportingEntryPublished()` or `fileEntryPublished()` - method, respectively. This allows them to be viewed in IDEs or included in reports. -+ -In JUnit Jupiter you should use `TestReporter` where you used to print information to -`stdout` or `stderr` in JUnit 4. Some IDEs print report entries to `stdout` or display -them in the user interface for test results. - -[source,java,indent=0] ----- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] ----- - -NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. - -Check out the `{RandomParametersExtension}` for an example of a custom -`{ParameterResolver}`. While not intended to be production-ready, it demonstrates the -simplicity and expressiveness of both the extension model and the parameter resolution -process. `MyRandomParametersTest` demonstrates how to inject random values into `@Test` -methods. - -[source,java,indent=0] ----- -@ExtendWith(RandomParametersExtension.class) -class MyRandomParametersTest { - - @Test - void injectsInteger(@Random int i, @Random int j) { - assertNotEquals(i, j); - } - - @Test - void injectsDouble(@Random double d) { - assertEquals(0.0, d, 1.0); - } - -} ----- - -For real-world use cases, check out the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -When the type of the parameter to inject is the only condition for your -`{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. -The `supportsParameters` method is implemented behind the scenes and supports -parameterized types. - -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods - -JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, -`@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` -methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a -test interface or on interface `default` methods _if_ the test interface or test class is -annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. - -[source,java] ----- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ----- - -`@ExtendWith` and `@Tag` can be declared on a test interface so that classes that -implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. - -[source,java] ----- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ----- - -In your test class you can then implement these test interfaces to have them applied. - -[source,java] ----- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ----- - -Running the `TestInterfaceDemo` results in output similar to the following: - -.... -INFO example.TestLifecycleLogger - Before all tests -INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()] -INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms. -INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()] -INFO example.TestLifecycleLogger - About to execute [isEqualValue()] -INFO example.TimingExtension - Method [isEqualValue] took 1 ms. -INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] -INFO example.TestLifecycleLogger - After all tests -.... - -Another possible application of this feature is to write tests for interface contracts. -For example, you can write tests for how implementations of `Object.equals` or -`Comparable.compareTo` should behave as follows. - -[source,java] ----- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] ----- - -[source,java] ----- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] ----- - -In your test class you can then implement both contract interfaces thereby inheriting the -corresponding tests. Of course you'll have to implement the abstract methods. - -[source,java] ----- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] ----- - -NOTE: The above tests are merely meant as examples and therefore not complete. - - -[[writing-tests-repeated-tests]] -=== Repeated Tests - -JUnit Jupiter provides the ability to repeat a test a specified number of times by -annotating a method with `@RepeatedTest` and specifying the total number of repetitions -desired. Each invocation of a repeated test behaves like the execution of a regular -`@Test` method with full support for the same lifecycle callbacks and extensions. - -The following example demonstrates how to declare a test named `repeatedTest()` that -will be automatically repeated 10 times. - -[source,java] ----- -@RepeatedTest(10) -void repeatedTest() { - // ... -} ----- - -`@RepeatedTest` can be configured with a failure threshold which signifies the number of -failures after which remaining repetitions will be automatically skipped. Set the -`failureThreshold` attribute to a positive number less than the total number of -repetitions in order to skip the invocations of remaining repetitions after the specified -number of failures has been encountered. - -For example, if you are using `@RepeatedTest` to repeatedly invoke a test that you suspect -to be _flaky_, a single failure is sufficient to demonstrate that the test is flaky, and -there is no need to invoke the remaining repetitions. To support that specific use case, -set `failureThreshold = 1`. You can alternatively set the threshold to a number greater -than 1 depending on your use case. - -By default, the `failureThreshold` attribute is set to `Integer.MAX_VALUE`, signaling that -no failure threshold will be applied, which effectively means that the specified number of -repetitions will be invoked regardless of whether any repetitions fail. - -WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no -guarantees can be made regarding the failure threshold. It is therefore recommended that a -`@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. - -In addition to specifying the number of repetitions and failure threshold, a custom -display name can be configured for each repetition via the `name` attribute of the -`@RepeatedTest` annotation. Furthermore, the display name can be a pattern composed of a -combination of static text and dynamic placeholders. The following placeholders are -currently supported. - -- `+{displayName}+`: display name of the `@RepeatedTest` method -- `+{currentRepetition}+`: the current repetition count -- `+{totalRepetitions}+`: the total number of repetitions - -The default display name for a given repetition is generated based on the following -pattern: `"repetition +{currentRepetition}+ of +{totalRepetitions}+"`.Thus, the display -names for individual repetitions of the previous `repeatedTest()` example would be: -`repetition 1 of 10`, `repetition 2 of 10`, etc.If you would like the display name of -the `@RepeatedTest` method included in the name of each repetition, you can define your -own custom pattern or use the predefined `RepeatedTest.LONG_DISPLAY_NAME` pattern.The -latter is equal to `"+{displayName}+ :: repetition +{currentRepetition}+ of -+{totalRepetitions}+"` which results in display names for individual repetitions like -`repeatedTest() :: repetition 1 of 10`, `repeatedTest() :: repetition 2 of 10`, etc. - -In order to retrieve information about the current repetition, the total number of -repetitions, the number of repetitions that have failed, and the failure threshold, a -developer can choose to have an instance of `{RepetitionInfo}` injected into a -`@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. - -[[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples - -The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of -repeated tests. - -The `repeatedTest()` method is identical to the example from the previous section; whereas, -`repeatedTestWithRepetitionInfo()` demonstrates how to have an instance of -`RepetitionInfo` injected into a test to access the total number of repetitions for the -current repeated test. - -`repeatedTestWithFailureThreshold()` demonstrates how to set a failure threshold and -simulates an unexpected failure for every second repetition.The resulting behavior can be -viewed in the `ConsoleLauncher` output at the end of this section. - -The next two methods demonstrate how to include a custom `@DisplayName` for the -`@RepeatedTest` method in the display name of each repetition. `customDisplayName()` -combines a custom display name with a custom pattern and then uses `TestInfo` to verify -the format of the generated display name. `Repeat!` is the `+{displayName}+` which comes -from the `@DisplayName` declaration, and `1/1` comes from -`+{currentRepetition}+/+{totalRepetitions}+`.In contrast, -`customDisplayNameWithLongPattern()` uses the aforementioned predefined -`RepeatedTest.LONG_DISPLAY_NAME` pattern. - -`repeatedTestInGerman()` demonstrates the ability to translate display names of repeated -tests into foreign languages -- in this case German, resulting in names for individual -repetitions such as: `Wiederholung 1 von 5`, `Wiederholung 2 von 5`, etc. - -Since the `beforeEach()` method is annotated with `@BeforeEach` it will get executed -before each repetition of each repeated test. By having the `TestInfo` and -`RepetitionInfo` injected into the method, we see that it's possible to obtain -information about the currently executing repeated test. Executing `RepeatedTestsDemo` -with the `INFO` log level enabled results in the following output. - -.... -INFO: About to execute repetition 1 of 10 for repeatedTest -INFO: About to execute repetition 2 of 10 for repeatedTest -INFO: About to execute repetition 3 of 10 for repeatedTest -INFO: About to execute repetition 4 of 10 for repeatedTest -INFO: About to execute repetition 5 of 10 for repeatedTest -INFO: About to execute repetition 6 of 10 for repeatedTest -INFO: About to execute repetition 7 of 10 for repeatedTest -INFO: About to execute repetition 8 of 10 for repeatedTest -INFO: About to execute repetition 9 of 10 for repeatedTest -INFO: About to execute repetition 10 of 10 for repeatedTest -INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo -INFO: About to execute repetition 1 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 2 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 3 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 4 of 8 for repeatedTestWithFailureThreshold -INFO: About to execute repetition 1 of 1 for customDisplayName -INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern -INFO: About to execute repetition 1 of 5 for repeatedTestInGerman -INFO: About to execute repetition 2 of 5 for repeatedTestInGerman -INFO: About to execute repetition 3 of 5 for repeatedTestInGerman -INFO: About to execute repetition 4 of 5 for repeatedTestInGerman -INFO: About to execute repetition 5 of 5 for repeatedTestInGerman -.... - -[source,java] ----- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] ----- - -When using the `ConsoleLauncher` with the unicode theme enabled, execution of -`RepeatedTestsDemo` results in the following output to the console. - -.... -├─ RepeatedTestsDemo ✔ -│ ├─ repeatedTest() ✔ -│ │ ├─ repetition 1 of 10 ✔ -│ │ ├─ repetition 2 of 10 ✔ -│ │ ├─ repetition 3 of 10 ✔ -│ │ ├─ repetition 4 of 10 ✔ -│ │ ├─ repetition 5 of 10 ✔ -│ │ ├─ repetition 6 of 10 ✔ -│ │ ├─ repetition 7 of 10 ✔ -│ │ ├─ repetition 8 of 10 ✔ -│ │ ├─ repetition 9 of 10 ✔ -│ │ └─ repetition 10 of 10 ✔ -│ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 5 ✔ -│ │ ├─ repetition 2 of 5 ✔ -│ │ ├─ repetition 3 of 5 ✔ -│ │ ├─ repetition 4 of 5 ✔ -│ │ └─ repetition 5 of 5 ✔ -│ ├─ repeatedTestWithFailureThreshold(RepetitionInfo) ✔ -│ │ ├─ repetition 1 of 8 ✔ -│ │ ├─ repetition 2 of 8 ✘ Boom! -│ │ ├─ repetition 3 of 8 ✔ -│ │ ├─ repetition 4 of 8 ✘ Boom! -│ │ ├─ repetition 5 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 6 of 8 ↷ Failure threshold [2] exceeded -│ │ ├─ repetition 7 of 8 ↷ Failure threshold [2] exceeded -│ │ └─ repetition 8 of 8 ↷ Failure threshold [2] exceeded -│ ├─ Repeat! ✔ -│ │ └─ Repeat! 1/1 ✔ -│ ├─ Details... ✔ -│ │ └─ Details... :: repetition 1 of 1 ✔ -│ └─ repeatedTestInGerman() ✔ -│ ├─ Wiederholung 1 von 5 ✔ -│ ├─ Wiederholung 2 von 5 ✔ -│ ├─ Wiederholung 3 von 5 ✔ -│ ├─ Wiederholung 4 von 5 ✔ -│ └─ Wiederholung 5 von 5 ✔ -.... - - -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests - -_Parameterized tests_ make it possible to run a test method multiple times with different -arguments. They are declared just like regular `@Test` methods but use the -`{ParameterizedTest}` annotation instead. - -_Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just -like regular test classes and may contain any supported test method type (including -`@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. - -WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will -provide the arguments for each invocation and then -<> the arguments in the -parameterized method or class, respectively. - -The following example demonstrates a parameterized test that uses the `@ValueSource` -annotation to specify a `String` array as the source of arguments. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] ----- - -When executing the above parameterized test method, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -palindromes(String) ✔ -├─ [1] candidate = "racecar" ✔ -├─ [2] candidate = "radar" ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ -.... - -The same `@ValueSource` annotation can be used to specify the source of arguments for a -`@ParameterizedClass`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] ----- - -When executing the above parameterized test class, each invocation will be reported -separately. For instance, the `ConsoleLauncher` will print output similar to the -following. - -.... -PalindromeTests ✔ -├─ [1] candidate = "racecar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -├─ [2] candidate = "radar" ✔ -│ ├─ palindrome() ✔ -│ └─ reversePalindrome() ✔ -└─ [3] candidate = "able was I ere I saw elba" ✔ - ├─ palindrome() ✔ - └─ reversePalindrome() ✔ -.... - -[[writing-tests-parameterized-tests-setup]] -==== Required Setup - -In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. - -[[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments - -[[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests - -Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between -argument source index and method parameter index (see examples in -<>). However, a parameterized test -method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). -Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an -instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method -must declare formal parameters according to the following rules. - -* Zero or more _indexed parameters_ must be declared first. -* Zero or more _aggregators_ must be declared next. -* Zero or more arguments supplied by a `ParameterResolver` must be declared last. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is passed as an argument to the -parameterized method at the same index in the method's formal parameter list. An -_aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated -with `{AggregateWith}`. - -[[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes - -Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via -field injection. If a `{Parameter}`-annotated field is declared in the parameterized class -or one of its superclasses, field injection will be used. Otherwise, constructor injection -will be used. - -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection - -WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> -with the `PER_CLASS` mode instead. - -For constructor injection, the same rules apply as defined for -<> -above. In the following example, two arguments are injected into the constructor of the -test class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] ----- - -You may use _records_ to implement parameterized classes that avoid the boilerplate code -of declaring a test class constructor. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] ----- - -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection - -For field injection, the following rules apply for fields annotated with `@Parameter`. - -* Zero or more _indexed parameters_ may be declared; each must have a unique index - specified in its `@Parameter(index)` annotation. The index may be omitted if there is - only one indexed parameter. If there are at least two indexed parameter declarations, - there must be declarations for all indexes from 0 to the largest declared index. -* Zero or more _aggregators_ may be declared; each without specifying an index in its - `@Parameter` annotation. -* Zero or more other fields may be declared as usual as long as they're not annotated with - `@Parameter`. - -In this context, an _indexed parameter_ is an argument for a given index in the -`{Arguments}` provided by an `{ArgumentsProvider}` that is injected into a field annotated -with `@Parameter(index)`. An _aggregator_ is any `@Parameter`-annotated field of type -{ArgumentsAccessor} or any field annotated with {AggregateWith}. - -The following example demonstrates how to use field injection to consume multiple -arguments in a parameterized class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] ----- - -If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> -may resolve constructor parameters as usual, though. - -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] -====== Lifecycle Methods - -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also -be used to consume arguments if their `injectArguments` attribute is set to `true` (the -default). If so, their method signatures must follow the same rules apply as defined for -<> and -additionally use the same parameter types as the _indexed parameters_ of the parameterized -test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and -`{AfterParameterizedClassInvocation}` for details and to the -<> section for an -example. - -[NOTE] -.AutoCloseable arguments -==== -Arguments that implement `java.lang.AutoCloseable` (or `java.io.Closeable` which extends -`java.lang.AutoCloseable`) will be automatically closed after the parameterized class or -test invocation. - -To prevent this from happening, set the `autoCloseArguments` attribute in -`@ParameterizedTest` to `false`. Specifically, if an argument that implements -`AutoCloseable` is reused for multiple invocations of the same parameterized class or test -method, you must specify the `autoCloseArguments = false` on the `{ParameterizedClass}` or -`{ParameterizedTest}` annotation to ensure that the argument is not closed between -invocations. -==== - -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] -===== Other Extensions - -Other extensions can access the parameters and resolved arguments of a parameterized test -or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. -Please refer to the Javadoc of `{ParameterInfo}` for details. - -[[writing-tests-parameterized-tests-sources]] -==== Sources of Arguments - -Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the -following subsections provides a brief overview and an example for each of them. Please -refer to the Javadoc in the `{params-provider-package}` package for additional -information. - -TIP: All source annotations in this section are applicable to both `{ParameterizedClass}` -and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only -show how to use them with `{ParameterizedTest}` methods. - -[[writing-tests-parameterized-tests-sources-ValueSource]] -===== @ValueSource - -`@ValueSource` is one of the simplest possible sources. It lets you specify a single -array of literal values and can only be used for providing a single argument per -parameterized test invocation. - -The following types of literal values are supported by `@ValueSource`. - -- `short` -- `byte` -- `int` -- `long` -- `float` -- `double` -- `char` -- `boolean` -- `java.lang.String` -- `java.lang.Class` - -For example, the following `@ParameterizedTest` method will be invoked three times, with -the values `1`, `2`, and `3` respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ValueSource_example] ----- - -[[writing-tests-parameterized-tests-sources-null-and-empty]] -===== Null and Empty Sources - -In order to check corner cases and verify proper behavior of our software when it is -supplied _bad input_, it can be useful to have `null` and _empty_ values supplied to our -parameterized tests. The following annotations serve as sources of `null` and empty values -for parameterized tests that accept a single argument. - -* `{NullSource}`: provides a single `null` argument to the annotated `@ParameterizedClass` - or `@ParameterizedTest`. - - `@NullSource` cannot be used for a parameter that has a primitive type. -* `{EmptySource}`: provides a single _empty_ argument to the annotated - `@ParameterizedClass` or `@ParameterizedTest` for parameters of the following types: - `java.lang.String`, `java.util.Collection` (and concrete subtypes with a `public` no-arg - constructor), `java.util.List`, `java.util.Set`, `java.util.SortedSet`, - `java.util.NavigableSet`, `java.util.Map` (and concrete subtypes with a `public` no-arg - constructor), `java.util.SortedMap`, `java.util.NavigableMap`, primitive arrays (e.g., - `int[]`, `char[][]`, etc.), object arrays (e.g., `String[]`, `Integer[][]`, etc.). -* `{NullAndEmptySource}`: a _composed annotation_ that combines the functionality of - `@NullSource` and `@EmptySource`. - -If you need to supply multiple varying types of _blank_ strings to a parameterized -class or test, you can achieve that using -<> -- for example, -`@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. - -You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider -range of `null`, _empty_, and _blank_ input. The following example demonstrates how to -achieve this for strings. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example1] ----- - -Making use of the composed `@NullAndEmptySource` annotation simplifies the above as -follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=NullAndEmptySource_example2] ----- - -NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test method -result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit -blank strings supplied via `@ValueSource`. - -[[writing-tests-parameterized-tests-sources-EnumSource]] -===== @EnumSource - -`@EnumSource` provides a convenient way to use `Enum` constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example] ----- - -The annotation's `value` attribute is optional. When omitted, the declared type of the -first parameter is used. The test will fail if it does not reference an enum type. -Thus, the `value` attribute is required in the above example because the method parameter -is declared as `TemporalUnit`, i.e. the interface implemented by `ChronoUnit`, which isn't -an enum type. Changing the method parameter type to `ChronoUnit` allows you to omit the -explicit enum type from the annotation as follows. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_autodetection] ----- - -The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ----- - -In addition to `names`, you can use the `from` and `to` attributes to specify a range of -constants. The range starts from the constant specified in the `from` attribute and -includes all subsequent constants up to and including the one specified in the `to` -attribute, based on the natural order of the enum constants. - -If `from` and `to` attributes are omitted, they default to the first and last constants -in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, -all constants will be used. The following example demonstrates how to specify a range of -constants. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] ----- - -The `@EnumSource` annotation also provides an optional `mode` attribute that enables -fine-grained control over which constants are passed to the test method. For example, you -can exclude names from the enum constant pool or specify regular expressions as in the -following examples. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ----- - -You can also combine `mode` with the `from`, `to` and `names` attributes to define a -range of constants while excluding specific values from that range as shown below. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ----- - -[[writing-tests-parameterized-tests-sources-MethodSource]] -===== @MethodSource - -`{MethodSource}` allows you to refer to one or more _factory_ methods of the test class -or external classes. - -Factory methods within the test class must be `static` unless the test class is annotated -with `@TestInstance(Lifecycle.PER_CLASS)`; whereas, factory methods in external classes -must always be `static`. - -Each factory method must generate a _stream_ of _arguments_, and each set of arguments -within the stream will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. Generally speaking this -translates to a `Stream` of `Arguments` (i.e., `Stream`); however, the actual -concrete return type can take on many forms. In this context, a "stream" is anything that -JUnit can reliably convert into a `Stream`, such as `Stream`, `DoubleStream`, -`LongStream`, `IntStream`, `Collection`, `Iterator`, `Iterable`, an array of objects or -primitives, or any type that provides an `iterator(): Iterator` method (such as, for -example, a `kotlin.sequences.Sequence`). The "arguments" within the stream can be supplied -as an instance of `Arguments`, an array of objects (e.g., `Object[]`), or a single value -if the parameterized class or test method accepts a single argument. - -If the return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -If you only need a single parameter, you can return a `Stream` of instances of the -parameter type as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_example] ----- - -For a `@ParameterizedClass`, providing a factory method name via `@MethodSource` is -mandatory. For a `@ParameterizedTest`, if you do not explicitly provide a factory method -name, JUnit Jupiter will search for a _factory_ method with the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=simple_MethodSource_without_value_example] ----- - -Streams for primitive types (`DoubleStream`, `IntStream`, and `LongStream`) are also -supported as demonstrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=primitive_MethodSource_example] ----- - -If a parameterized class or test method declares multiple parameters, you need to return a -collection, stream, or array of `Arguments` instances or object arrays as shown below (see -the Javadoc for `{MethodSource}` for further details on supported return types). Note that -`arguments(Object...)` is a static factory method defined in the `Arguments` interface. In -addition, `Arguments.of(Object...)` may be used as an alternative to -`arguments(Object...)`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_MethodSource_example] ----- - -An external, `static` _factory_ method can be referenced by providing its _fully qualified -method name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -package example; - -include::{testDir}/example/ExternalMethodSourceDemo.java[tags=external_MethodSource_example] ----- - -Factory methods can declare parameters, which will be provided by registered -implementations of the `ParameterResolver` extension API. In the following example, the -factory method is referenced by its name since there is only one such method in the test -class. If there are several local methods with the same name, parameters can also be -provided to differentiate them – for example, `@MethodSource("factoryMethod()")` or -`@MethodSource("factoryMethod(java.lang.String)")`. Alternatively, the factory method -can be referenced by its fully qualified method name, e.g. -`@MethodSource("example.MyTests#factoryMethod(java.lang.String)")`. - -[source,java,indent=0] ----- -include::{testDir}/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ----- - -[[writing-tests-parameterized-tests-sources-FieldSource]] -===== @FieldSource - -`{FieldSource}` allows you to refer to one or more fields of the test class or external -classes. - -Fields within the test class must be `static` unless the test class is annotated with -`@TestInstance(Lifecycle.PER_CLASS)`; whereas, fields in external classes must always be -`static`. - -Each field must be able to supply a _stream_ of arguments, and each set of "arguments" -within the "stream" will be provided as the physical arguments for individual invocations -of the annotated `@ParameterizedClass` or `@ParameterizedTest`. - -In this context, a "stream" is anything that JUnit can reliably convert to a `Stream`; -however, the actual concrete field type can take on many forms. Generally speaking this -translates to a `Collection`, an `Iterable`, a `Supplier` of a stream (`Stream`, -`DoubleStream`, `LongStream`, or `IntStream`), a `Supplier` of an `Iterator`, an array of -objects or primitives, or any type that provides an `iterator(): Iterator` method (such -as, for example, a `kotlin.sequences.Sequence`). Each set of "arguments" within the -"stream" can be supplied as an instance of `Arguments`, an array of objects (for example, -`Object[]`, `String[]`, etc.), or a single value if the parameterized class or test method accepts -a single argument. - -[WARNING] -==== -In contrast to the supported return types for -<> factory -methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, -`DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types -are _consumed_ the first time they are processed. However, if you wish to use one of -these types, you can wrap it in a `Supplier` — for example, `Supplier`. -==== - -If the `Supplier` return type is `Stream` or one of the primitive streams, -JUnit will properly close it by calling `BaseStream.close()`, -making it safe to use a resource such as `Files.lines()`. - -Please note that a one-dimensional array of objects supplied as a set of "arguments" will -be handled differently than other types of arguments. Specifically, all the elements of a -one-dimensional array of objects will be passed as individual physical arguments to the -`@ParameterizedClass` or `@ParameterizedTest`. See the Javadoc for `{FieldSource}` for -further details. - -For a `@ParameterizedClass`, providing a field name via `@FieldSource` is mandatory. For a -`@ParameterizedTest`, if you do not explicitly provide a field name, JUnit Jupiter will -search in the test class for a field that has the same name as the current -`@ParameterizedTest` method by convention. This is demonstrated in the following example. -This parameterized test method will be invoked twice: with the values `"apple"` and -`"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=default_field_FieldSource_example] ----- - -The following example demonstrates how to provide a single explicit field name via -`@FieldSource`. This parameterized test method will be invoked twice: with the values -`"apple"` and `"banana"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_field_FieldSource_example] ----- - -The following example demonstrates how to provide multiple explicit field names via -`@FieldSource`. This example uses the `listOfFruits` field from the previous example as -well as the `additionalFruits` field. Consequently, this parameterized test method will -be invoked four times: with the values `"apple"`, `"banana"`, `"cherry"`, and -`"dewberry"`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multiple_fields_FieldSource_example] ----- - -It is also possible to provide a `Stream`, `DoubleStream`, `IntStream`, `LongStream`, or -`Iterator` as the source of arguments via a `@FieldSource` field as long as the stream or -iterator is wrapped in a `java.util.function.Supplier`. The following example demonstrates -how to provide a `Supplier` of a `Stream` of named arguments. This parameterized test -method will be invoked twice: with the values `"apple"` and `"banana"` and with display -names `"Apple"` and `"Banana"`, respectively. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -If a parameterized class or test method declares multiple parameters, the corresponding -`@FieldSource` field must be able to provide a collection, stream supplier, or array of -`Arguments` instances or object arrays as shown below (see the Javadoc for `{FieldSource}` -for further details on supported types). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=multi_arg_FieldSource_example] ----- - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -An external, `static` `@FieldSource` field can be referenced by providing its -_fully qualified field name_ as demonstrated in the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ----- - -[[writing-tests-parameterized-tests-sources-CsvSource]] -===== @CsvSource - -`@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV -`String` literals). Each string provided via the `value` attribute in `@CsvSource` -represents a CSV record and results in one invocation of the parameterized class or -test. The first record may optionally be used to supply CSV headers (see the Javadoc for -the `useHeadersInDisplayName` attribute for details and an example). - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvSource_example] ----- - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -By default, `@CsvSource` uses a single quote (`'`) as its quote character, but this can be -changed via the `quoteCharacter` attribute. See the `'lemon, lime'` value in the example -above and in the table below. An empty, quoted value (`''`) results in an empty `String` -unless the `emptyValue` attribute is set; whereas, an entirely _empty_ value is -interpreted as a `null` reference. By specifying one or more `nullValues`, a custom value -can be interpreted as a `null` reference (see the `NIL` example in the table below). An -`ArgumentConversionException` is thrown if the target type of a `null` reference is a -primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[cols="50,50"] -|=== -| Example Input | Resulting Argument List - -| `@CsvSource({ "apple, banana" })` | `"apple"`, `"banana"` -| `@CsvSource({ "apple, 'lemon, lime'" })` | `"apple"`, `"lemon, lime"` -| `@CsvSource({ "apple, ''" })` | `"apple"`, `""` -| `@CsvSource({ "apple, " })` | `"apple"`, `null` -| `@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL")` | `"apple"`, `"banana"`, `null` -| `@CsvSource(value = { " apple , banana" }, ignoreLeadingAndTrailingWhitespace = false)` | `" apple "`, `" banana"` -|=== - -If the programming language you are using supports Java _text blocks_ or equivalent -multi-line string literals, you can alternatively use the `textBlock` attribute of -`@CsvSource`. Each record within a text block represents a CSV record and results in one -invocation of the parameterized class or test. The first record may optionally be used to -supply CSV headers by setting the `useHeadersInDisplayName` attribute to `true` as in the -example below. - -Using a text block, the previous example can be implemented as follows. - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(useHeadersInDisplayName = true, textBlock = """ - FRUIT, RANK - apple, 1 - banana, 2 - 'lemon, lime', 0xF1 - strawberry, 700_000 - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -The generated display names for the previous example include the CSV header names. - ----- -[1] FRUIT = "apple", RANK = "1" -[2] FRUIT = "banana", RANK = "2" -[3] FRUIT = "lemon, lime", RANK = "0xF1" -[4] FRUIT = "strawberry", RANK = "700_000" ----- - -In contrast to CSV records supplied via the `value` attribute, a text block can contain -comments. Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be treated as a comment and ignored. Note that there is one exception -to this rule: if the comment character appears within a quoted field, it loses -its special meaning. - -The comment character must be the first character on the line without any leading -whitespace. It is therefore recommended that the closing text block delimiter (`"""`) -be placed either at the end of the last line of input or on the following line, -left aligned with the rest of the input (as can be seen in the example below which -demonstrates formatting similar to a table). - -[source,java,indent=0] ----- -@ParameterizedTest -@CsvSource(delimiter = '|', quoteCharacter = '"', textBlock = """ - #----------------------------- - # FRUIT | RANK - #----------------------------- - apple | 1 - #----------------------------- - banana | 2 - #----------------------------- - "lemon lime" | 0xF1 - #----------------------------- - strawberry | 700_000 - #----------------------------- - """) -void testWithCsvSource(String fruit, int rank) { - // ... -} ----- - -[NOTE] -==== -Java's https://docs.oracle.com/en/java/javase/17/text-blocks/index.html[text block] -feature automatically removes _incidental whitespace_ when the code is compiled. -However other JVM languages such as Groovy and Kotlin do not. Thus, if you are using a -programming language other than Java and your text block contains comments or new lines -within quoted strings, you will need to ensure that there is no leading whitespace within -your text block. -==== - -[[writing-tests-parameterized-tests-sources-CsvFileSource]] -===== @CsvFileSource - -`@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the -local file system. Each record from a CSV file results in one invocation of the -parameterized class or test. The first record may optionally be used to supply CSV -headers. You can instruct JUnit to ignore the headers via the `numLinesToSkip` attribute. -If you would like for the headers to be used in the display names, you can set the -`useHeadersInDisplayName` attribute to `true`. The examples below demonstrate the use of -`numLinesToSkip` and `useHeadersInDisplayName`. - -The default delimiter is a comma (`,`), but you can use another character by setting the -`delimiter` attribute. Alternatively, the `delimiterString` attribute allows you to use a -`String` delimiter instead of a single character. However, both delimiter attributes -cannot be set simultaneously. - -.Comments in CSV files -NOTE: Any line beginning with the value of the `commentCharacter` attribute (`+++#+++` -by default) will be interpreted as a comment and will be ignored. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=CsvFileSource_example] ----- - -[source,csv,indent=0] -.two-column.csv ----- -include::{testResourcesDir}/two-column.csv[] ----- - -The following listing shows the generated display names for the first two parameterized -test methods above. - ----- -[1] country = "Sweden", reference = "1" -[2] country = "Poland", reference = "2" -[3] country = "United States of America", reference = "3" -[4] country = "France", reference = "700_000" ----- - -The following listing shows the generated display names for the last parameterized test -method above that uses CSV header names. - ----- -[1] COUNTRY = "Sweden", REFERENCE = "1" -[2] COUNTRY = "Poland", REFERENCE = "2" -[3] COUNTRY = "United States of America", REFERENCE = "3" -[4] COUNTRY = "France", REFERENCE = "700_000" ----- - -In contrast to the default syntax used in `@CsvSource`, `@CsvFileSource` uses a double -quote (`+++"+++`) as the quote character by default, but this can be changed via the -`quoteCharacter` attribute. See the `"United States of America"` value in the example -above. An empty, quoted value (`+++""+++`) results in an empty `String` unless the -`emptyValue` attribute is set; whereas, an entirely _empty_ value is interpreted as a -`null` reference. By specifying one or more `nullValues`, a custom value can be -interpreted as a `null` reference. An `ArgumentConversionException` is thrown if the -target type of a `null` reference is a primitive type. - -NOTE: An _unquoted_ empty value will always be converted to a `null` reference regardless -of any custom values configured via the `nullValues` attribute. - -Except within a quoted string, leading and trailing whitespace in a CSV column is trimmed -by default. This behavior can be changed by setting the -`ignoreLeadingAndTrailingWhitespace` attribute to `true`. - -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] -===== @ArgumentsSource - -`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note -that an implementation of `ArgumentsProvider` must be declared as either a top-level -class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example] ----- - -If you wish to implement a custom `ArgumentsProvider` that also consumes an annotation -(like built-in providers such as `{ValueArgumentsProvider}` or `{CsvArgumentsProvider}`), -you have the possibility to extend the `{AnnotationBasedArgumentsProvider}` class. - -Moreover, `ArgumentsProvider` implementations may declare constructor parameters in case -they need to be resolved by a registered `ParameterResolver` as demonstrated in the -following example. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ----- - -[[writing-tests-parameterized-repeatable-sources]] -===== Multiple sources using repeatable annotations - -Repeatable annotations provide a convenient way to specify multiple sources from -different providers. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=repeatable_annotations] ----- - -Following the above parameterized test, a test case will run for each argument: - ----- -[1] foo -[2] bar ----- - -The following annotations are repeatable: - -* `@ValueSource` -* `@EnumSource` -* `@MethodSource` -* `@FieldSource` -* `@CsvSource` -* `@CsvFileSource` -* `@ArgumentsSource` - -[[writing-tests-parameterized-tests-argument-count-validation]] -==== Argument Count Validation - -By default, when an arguments source provides more arguments than the test method needs, -those additional arguments are ignored and the test executes as usual. -This can lead to bugs where arguments are never passed to the parameterized class or -method. - -To prevent this, you can set argument count validation to 'strict'. -Then, any additional arguments will cause an error instead. - -To change this behavior for all tests, set the -`junit.jupiter.params.argumentCountValidation` -<> to `strict`. -To change this behavior for a single parameterized class or test method, -use the `argumentCountValidation` attribute of the `@ParameterizedClass` or -`@ParameterizedTest` annotation: - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=argument_count_validation] ----- - -[[writing-tests-parameterized-tests-argument-conversion]] -==== Argument Conversion - -[[writing-tests-parameterized-tests-argument-conversion-widening]] -===== Widening Conversion - -JUnit Jupiter supports -https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2[Widening Primitive -Conversion] for arguments supplied to a `@ParameterizedClass` or `@ParameterizedTest`. -For example, a parameterized class or test method annotated with -`@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type -`int` but also an argument of type `long`, `float`, or `double`. - -[[writing-tests-parameterized-tests-argument-conversion-implicit]] -===== Implicit Conversion - -To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in -implicit type converters. The conversion process depends on the declared type of each -method parameter. - -For example, if a `@ParameterizedClass` or `@ParameterizedTest` declares a parameter -of type `TimeUnit` and the actual type supplied by the declared source is a `String`, the -string will be automatically converted into the corresponding `TimeUnit` enum constant. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_conversion_example] ----- - -`String` instances are implicitly converted to the following target types. - -NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their -integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. - -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] -[cols="10,90"] -|=== -| Target Type | Example - -| `boolean`/`Boolean` | `"true"` -> `true` _(only accepts values 'true' or 'false', case-insensitive)_ -| `byte`/`Byte` | `"15"`, `"0xF"`, or `"017"` -> `(byte) 15` -| `char`/`Character` | `"o"` -> `'o'` -| `short`/`Short` | `"15"`, `"0xF"`, or `"017"` -> `(short) 15` -| `int`/`Integer` | `"15"`, `"0xF"`, or `"017"` -> `15` -| `long`/`Long` | `"15"`, `"0xF"`, or `"017"` -> `15L` -| `float`/`Float` | `"1.0"` -> `1.0f` -| `double`/`Double` | `"1.0"` -> `1.0d` -| `Enum` subclass | `"SECONDS"` -> `TimeUnit.SECONDS` -| `java.io.File` | `"/path/to/file"` -> `new File("/path/to/file")` -| `java.lang.Class` | `"java.lang.Integer"` -> `java.lang.Integer.class` _(use `$` for nested classes, e.g. `"java.lang.Thread$State"`)_ -| `java.lang.Class` | `"byte"` -> `byte.class` _(primitive types are supported)_ -| `java.lang.Class` | `"char[]"` -> `char[].class` _(array types are supported)_ -| `java.math.BigDecimal` | `"123.456e789"` -> `new BigDecimal("123.456e789")` -| `java.math.BigInteger` | `"1234567890123456789"` -> `new BigInteger("1234567890123456789")` -| `java.net.URI` | `"https://junit.org/"` -> `URI.create("https://junit.org/")` -| `java.net.URL` | `"https://junit.org/"` -> `URI.create("https://junit.org/").toURL()` -| `java.nio.charset.Charset` | `"UTF-8"` -> `Charset.forName("UTF-8")` -| `java.nio.file.Path` | `"/path/to/file"` -> `Paths.get("/path/to/file")` -| `java.time.Duration` | `"PT3S"` -> `Duration.ofSeconds(3)` -| `java.time.Instant` | `"1970-01-01T00:00:00Z"` -> `Instant.ofEpochMilli(0)` -| `java.time.LocalDateTime` | `"2017-03-14T12:34:56.789"` -> `LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000)` -| `java.time.LocalDate` | `"2017-03-14"` -> `LocalDate.of(2017, 3, 14)` -| `java.time.LocalTime` | `"12:34:56.789"` -> `LocalTime.of(12, 34, 56, 789_000_000)` -| `java.time.MonthDay` | `"--03-14"` -> `MonthDay.of(3, 14)` -| `java.time.OffsetDateTime` | `"2017-03-14T12:34:56.789Z"` -> `OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.OffsetTime` | `"12:34:56.789Z"` -> `OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.Period` | `"P2M6D"` -> `Period.of(0, 2, 6)` -| `java.time.YearMonth` | `"2017-03"` -> `YearMonth.of(2017, 3)` -| `java.time.Year` | `"2017"` -> `Year.of(2017)` -| `java.time.ZonedDateTime` | `"2017-03-14T12:34:56.789Z"` -> `ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC)` -| `java.time.ZoneId` | `"Europe/Berlin"` -> `ZoneId.of("Europe/Berlin")` -| `java.time.ZoneOffset` | `"+02:30"` -> `ZoneOffset.ofHoursMinutes(2, 30)` -| `java.util.Currency` | `"JPY"` -> `Currency.getInstance("JPY")` -| `java.util.Locale` | `"en-US"` -> `Locale.forLanguageTag("en-US")` -| `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` -|=== - -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] -====== Fallback String-to-Object Conversion - -In addition to implicit conversion from strings to the target types listed in the above -table, JUnit Jupiter also provides a fallback mechanism for automatic conversion from a -`String` to a given target type if the target type declares exactly one suitable _factory -method_ or a _factory constructor_ as defined below. - -- __factory method__: a non-private, `static` method declared in the target type that - accepts either a single `String` argument or a single `CharSequence` argument and - returns an instance of the target type. The name of the method can be arbitrary and need - not follow any particular convention. -- __factory constructor__: a non-private constructor in the target type that accepts a - either a single `String` argument or a single `CharSequence` argument. Note that the - target type must be declared as either a top-level class or as a `static` nested class. - -NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory -method_ and a _factory constructor_ are discovered, the factory method will be used -instead of the constructor. - -For example, in the following `@ParameterizedTest` method, the `Book` argument will be -created by invoking the `Book.fromTitle(String)` factory method and passing `"42 Cats"` -as the title of the book. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ----- - -[[writing-tests-parameterized-tests-argument-conversion-explicit]] -===== Explicit Conversion - -Instead of relying on implicit argument conversion, you may explicitly specify an -`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation -like in the following example. Note that an implementation of `ArgumentConverter` must be -declared as either a top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter] ----- - -If the converter is only meant to convert one type to another, you can extend -`TypedArgumentConverter` to avoid boilerplate type checks. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_TypedArgumentConverter] ----- - -Explicit argument converters are meant to be implemented by test and extension authors. -Thus, `junit-jupiter-params` only provides a single explicit argument converter that may -also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the -composed annotation `JavaTimeConversionPattern`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_java_time_converter] ----- - -If you wish to implement a custom `ArgumentConverter` that also consumes an annotation -(like `JavaTimeArgumentConverter`), you have the possibility to extend the -`{AnnotationBasedArgumentConverter}` class. - -[[writing-tests-parameterized-tests-argument-aggregation]] -==== Argument Aggregation - -By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` -corresponds to a single method parameter. Consequently, argument sources which are -expected to supply a large number of arguments can lead to large constructor or method -signatures, respectively. - -In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using -this API, you can access the provided arguments through a single argument passed to your -test method. In addition, type conversion is supported as discussed in -<>. - -Besides, you can retrieve the current test invocation index with -`ArgumentsAccessor.getInvocationIndex()`. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_example] ----- - -_An instance of `ArgumentsAccessor` is automatically injected into any parameter of type -`ArgumentsAccessor`._ - -[[writing-tests-parameterized-tests-argument-aggregation-custom]] -===== Custom Aggregators - -Apart from direct access to the arguments of a `@ParameterizedClass` or -`@ParameterizedTest` using an `ArgumentsAccessor`, JUnit Jupiter also supports the usage -of custom, reusable _aggregators_. - -To use a custom aggregator, implement the `{ArgumentsAggregator}` interface and register -it via the `@AggregateWith` annotation on a compatible parameter of the -`@ParameterizedClass` or `@ParameterizedTest`. The result of the aggregation will then be -provided as an argument for the corresponding parameter when the parameterized test is -invoked. Note that an implementation of `ArgumentsAggregator` must be declared as either a -top-level class or as a `static` nested class. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator] ----- - -If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for -multiple parameterized classes or methods across your codebase, you may wish to create a -custom _composed annotation_ such as `@CsvToMyType` that is meta-annotated with -`@AggregateWith(MyTypeAggregator.class)`. The following example demonstrates this in -action with a custom `@CsvToPerson` annotation. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson] ----- - - -[[writing-tests-parameterized-tests-display-names]] -==== Customizing Display Names - -By default, the display name of a parameterized class or test invocation contains the -invocation index and a comma-separated list of the `String` representations of all -arguments for that specific invocation. If parameter names are present in the bytecode, -each argument will be preceded by its parameter name and an equals sign (unless the -argument is only available via an `ArgumentsAccessor` or `ArgumentAggregator`) – for -example, `firstName = "Jane"`. - -[TIP] -==== -To ensure that parameter names are present in the bytecode, test code must be compiled -with the `-parameters` compiler flag for Java or with the `-java-parameters` compiler flag -for Kotlin. -==== - -However, you can customize invocation display names via the `name` attribute of the -`@ParameterizedClass` or `@ParameterizedTest` annotation as in the following example. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=custom_display_names] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -Display name of container ✔ -├─ 1 ==> the rank of "apple" is "1" ✔ -├─ 2 ==> the rank of "banana" is "2" ✔ -└─ 3 ==> the rank of "lemon, lime" is "3" ✔ -.... -====== - -[NOTE] -==== -Please note that `name` is a `MessageFormat` pattern. Thus, a single quote (`'`) needs to -be represented as a doubled single quote (`''`) in order to be displayed. -==== - -The following placeholders are supported within custom display names. - -[cols="20,80"] -|=== -| Placeholder | Description - -| `\{displayName}` | the display name of the method -| `\{index}` | the current invocation index (1-based) -| `\{arguments}` | the complete, comma-separated arguments list -| `\{argumentsWithNames}` | the complete, comma-separated arguments list with parameter names -| `\{argumentSetName}` | the name of the argument set -| `\{argumentSetNameOrArgumentsWithNames}` | `\{argumentSetName}` or `\{argumentsWithNames}`, depending on how the arguments are supplied -| `\{0}`, `\{1}`, ... | an individual argument -|=== - -NOTE: When including arguments in display names, their string representations are truncated -if they exceed the configured maximum length. The limit is configurable via the -`junit.jupiter.params.displayname.argument.maxlength` configuration parameter and defaults -to 512 characters. - -When using `@MethodSource`, `@FieldSource`, or `@ArgumentsSource`, you can provide custom -names for individual arguments or custom names for entire sets of arguments. - -Use the `{Named}` API to provide a custom name for an individual argument, and the custom -name will be used if the argument is included in the invocation display name, like in the -example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_arguments] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named arguments ✔ -├─ 1: An important file ✔ -└─ 2: Another file ✔ -.... -====== - -[NOTE] -==== -Note that `arguments(Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. - -Similarly, `named(String, Object)` is a static factory method defined in the -`org.junit.jupiter.api.Named` interface. -==== - -Use the `ArgumentSet` API to provide a custom name for the entire set of arguments, and -the custom name will be used as the display name, like in the example below. - -====== -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=named_argument_set] ----- - -When executing the above method using the `ConsoleLauncher` you will see output similar to -the following. - -.... -A parameterized test with named argument sets ✔ -├─ [1] Important files ✔ -└─ [2] Other files ✔ -.... -====== - -[NOTE] -==== -Note that `argumentSet(String, Object...)` is a static factory method defined in the -`org.junit.jupiter.params.provider.Arguments` interface. -==== - -[[writing-tests-parameterized-tests-display-names-quoted-text]] -===== Quoted Text-based Arguments - -As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are -quoted by default. In this context, any `CharSequence` (such as a `String`) or `Character` -is considered text. A `CharSequence` is wrapped in double quotes (`"`), and a `Character` -is wrapped in single quotes (`'`). - -Special characters will be escaped in the quoted text. For example, carriage returns and -line feeds will be escaped as `\\r` and `\\n`, respectively. - -[TIP] -==== -This feature can be disabled by setting the `quoteTextArguments` attributes in -`@ParameterizedClass` and `@ParameterizedTest` to `false`. -==== - -For example, given a string argument `"line 1\nline 2"`, the physical representation in -the display name will be `"\"line 1\\nline 2\""` which is printed as `"line 1\nline 2"`. -Similarly, given a string argument `"\t"`, the physical representation in the display name -will be `"\"\\t\""` which is printed as `"\t"` instead of a blank string or invisible tab -character. The same applies for a character argument `'\t'`, whose physical representation -in the display name would be `"'\\t'"` which is printed as `'\t'`. - -For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` -parameterized test method from the -<> section above, the following -display names are generated. - ----- -[1] text = null -[2] text = "" -[3] text = " " -[4] text = " " -[5] text = "\t" -[6] text = "\n" ----- - -If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the -following display names are generated. - ----- -[1] fruit = "apple", rank = "1" -[2] fruit = "banana", rank = "2" -[3] fruit = "lemon, lime", rank = "0xF1" -[4] fruit = "strawberry", rank = "700_000" ----- - -[NOTE] -==== -The original source arguments are quoted when generating a display name, and this occurs -before any implicit or explicit argument conversion is performed. - -For example, if a parameterized test accepts `3.14` as a `float` argument that was -converted from `"3.14"` as an input string, `"3.14"` will be present in the display name -instead of `3.14`. You can see the effect of this with the `rank` values in the above -example. -==== - -[[writing-tests-parameterized-tests-display-names-default-pattern]] -===== Default Display Name Pattern - -If you'd like to set a default name pattern for all parameterized classes and tests in -your project, you can declare the `junit.jupiter.params.displayname.default` configuration -parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). - -[source,properties,indent=0] ----- -junit.jupiter.params.displayname.default = {index} ----- - -[[writing-tests-parameterized-tests-display-names-precedence-rules]] -===== Precedence Rules - -The display name for a parameterized class or test is determined according to the -following precedence rules: - -1. `name` attribute in `@ParameterizedClass` or `@ParameterizedTest`, if present -2. value of the `junit.jupiter.params.displayname.default` configuration parameter, if present -3. `DEFAULT_DISPLAY_NAME` constant defined in - `org.junit.jupiter.params.ParameterizedInvocationConstants` - -[[writing-tests-parameterized-tests-lifecycle-interop]] -==== Lifecycle and Interoperability - -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] -===== Parameterized Tests - -Each invocation of a parameterized test has the same lifecycle as a regular `@Test` -method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the -test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` -methods within the same test class. - -You may use `ParameterResolver` extensions with `@ParameterizedTest` methods. However, -method parameters that are resolved by argument sources need to come first in the -parameter list. Since a test class may contain regular tests as well as parameterized -tests with different parameter lists, values from argument sources are not resolved for -lifecycle methods (e.g. `@BeforeEach`) and test class constructors. - -[source,java,indent=0] ----- -include::{testDir}/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ----- - -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] -===== Parameterized Classes - -Each invocation of a parameterized class has the same lifecycle as a regular test class. -For example, `@BeforeAll` methods will be executed _once_ before all invocations and -`@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an -IDE. - -You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. -However, if constructor injection is used, constructor parameters that are resolved by -argument sources need to come first in the parameter list. Values from argument sources -are not resolved for regular lifecycle methods (e.g. `@BeforeEach`). - -In addition to regular lifecycle methods, parameterized classes may declare -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle -methods that are called once before/after each invocation of the parameterized class. -These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). - -These lifecycle methods may optionally declare parameters that are resolved depending on -the setting of the `injectArguments` annotation attribute. If it is set to `false`, the -parameters must be resolved by other registered {ParameterResolver} extensions. If the -attribute is set to `true` (the default), the method may declare parameters that match the -arguments of the parameterized class (see the Javadoc of -`{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for -details). This may, for example, be used to initialize the used arguments as demonstrated -by the following example. - -[source,java,indent=0] -.Using parameterized class lifecycle methods ----- -include::{testDir}/example/ParameterizedLifecycleDemo.java[tags=example] ----- -<1> Initialization of the argument _before_ each invocation of the parameterized class -<2> Usage of the previously initialized argument in a test method -<3> Validation and cleanup of the argument _after_ each invocation of the parameterized - class - -[[writing-tests-class-templates]] -=== Class Templates - -A `{ClassTemplate}` is not a regular test class but rather a template for the contained -test cases. As such, it is designed to be invoked multiple times depending on invocation -contexts returned by the registered providers. Thus, it must be used in conjunction with a -registered `{ClassTemplateInvocationContextProvider}` extension. -Each invocation of a class template behaves like the execution of a regular test class -with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> are a built-in -specialization of class templates. - -[[writing-tests-test-templates]] -=== Test Templates - -A `{TestTemplate}` method is not a regular test case but rather a template for a test -case. As such, it is designed to be invoked multiple times depending on the number of -invocation contexts returned by the registered providers. Thus, it must be used in -conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each -invocation of a test template method behaves like the execution of a regular `@Test` -method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. - -NOTE: <> and -<> are built-in specializations of -test templates. - -[[writing-tests-dynamic-tests]] -=== Dynamic Tests - -The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both -describe methods that implement test cases. These test cases are static in the sense that -they are fully specified at compile time, and their behavior cannot be changed by -anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but -are intentionally rather limited in their expressiveness._ - -In addition to these standard tests a completely new kind of test programming model has -been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is -generated at runtime by a factory method that is annotated with `@TestFactory`. - -In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but -rather a factory for test cases. Thus, a dynamic test is the product of a factory. -Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a -_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream" -is anything that JUnit can reliably convert into a `Stream`, such as `Stream`, -`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an -`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`). - -Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`. -`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child -nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes. -`DynamicTest` instances will be executed lazily, enabling dynamic and even -non-deterministic generation of test cases. - -Any `Stream` returned by a `@TestFactory` will be properly closed by calling -`stream.close()`, making it safe to use a resource such as `Files.lines()`. - -As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may -optionally declare parameters to be resolved by `ParameterResolvers`. - -A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_ -and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the -implementations of dynamic tests can be provided as _lambda expressions_ or _method -references_. - -.Dynamic Test Lifecycle -WARNING: The execution lifecycle of a dynamic test is quite different than it is for a -standard `@Test` case. Specifically, there are no lifecycle callbacks for individual -dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their -corresponding extension callbacks are executed for the `@TestFactory` method but not for -each _dynamic test_. In other words, if you access fields from the test instance within a -lambda expression for a dynamic test, those fields will not be reset by callback methods -or extensions between the execution of individual dynamic tests generated by the same -`@TestFactory` method. - -[[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples - -The following `DynamicTestsDemo` class demonstrates several examples of test factories -and dynamic tests. - -The first method returns an invalid return type and will cause a warning to be reported by -JUnit during test discovery. Such methods are not executed. - -The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`, -array, or `Stream` of `DynamicTest` instances. Most of these examples do not really -exhibit dynamic behavior but merely demonstrate the supported return types in principle. -However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to -generate dynamic tests for a given set of strings or a range of input numbers. - -The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an -`Iterator` that generates random numbers, a display name generator, and a test executor -and then provides all three to `DynamicTest.stream()`. Although the non-deterministic -behavior of `generateRandomNumberOfTests()` is of course in conflict with test -repeatability and should thus be used with care, it serves to demonstrate the -expressiveness and power of dynamic tests. - -The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility; -however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from -an existing `Stream` via the `DynamicTest.stream()` factory method. - -For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single -`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates -a nested hierarchy of dynamic tests utilizing `DynamicContainer`. - -[source,java] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named - -In some cases, it can be more natural to specify inputs together with a descriptive name -using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as -shown in the first example below. The second example takes it one step further and allows -to provide the code block that should be executed by implementing the `Executable` -interface along with `Named` via the `NamedExecutable` base class. - -[source,java] ----- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] ----- - -[[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests - -The JUnit Platform provides `TestSource`, a representation of the source of a test or -container used to navigate to its location by IDEs and build tools. - -The `TestSource` for a dynamic test or dynamic container can be constructed from a -`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI, -Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method, -respectively. The `URI` will be converted to one of the following `TestSource` -implementations. - -`ClasspathResourceSource` :: - If the `URI` contains the `classpath` scheme -- for example, - `classpath:/test/foo.xml?line=20,column=2`. - -`DirectorySource` :: - If the `URI` represents a directory present in the file system. - -`FileSource` :: - If the `URI` represents a file present in the file system. - -`MethodSource` :: - If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) -- - for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please - refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the - supported formats for a FQMN. - -`ClassSource` :: - If the `URI` contains the `class` scheme and the fully qualified class name -- - for example, `class:org.junit.Foo?line=42`. - -`UriSource` :: - If none of the above `TestSource` implementations are applicable. - -[[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution - -Dynamic tests and containers support -<>. You can configure their -`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` -factory methods as illustrated by the following example. - -[source,java,indent=0] ----- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] ----- - -Executing the above test factory method results in the following test tree and execution -modes: - -* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation) -** Container A -- `CONCURRENT` (from `@Execution` annotation) -*** not null -- `SAME_THREAD` (from `executionMode(...)` call) -*** properties -- `CONCURRENT` (from `@Execution` annotation) -**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) -**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) -** ... (same for "Container B" and "Container C") - [[writing-tests-declarative-timeouts]] === Timeouts @@ -3288,653 +160,3 @@ with `-agentlib:jdwp` or `-Xrunjdwp`. This heuristic is queried by the `disabled_on_debug` mode. -[[writing-tests-parallel-execution]] -=== Parallel Execution - -By default, JUnit Jupiter tests are run sequentially in a single thread; however, running -tests in parallel -- for example, to speed up execution -- is available as an opt-in -feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` -configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). - -Please note that enabling this property is only the first step required to execute tests -in parallel. If enabled, test classes and methods will still be executed sequentially by -default. Whether or not a node in the test tree is executed concurrently is controlled by -its execution mode. The following two modes are available. - -`SAME_THREAD`:: - Force execution in the same thread used by the parent. For example, when used on a test - method, the test method will be executed in the same thread as any `@BeforeAll` or - `@AfterAll` methods of the containing test class. - -`CONCURRENT`:: - Execute concurrently unless a resource lock forces execution in the same thread. - -By default, nodes in the test tree use the `SAME_THREAD` execution mode. You can change -the default by setting the `junit.jupiter.execution.parallel.mode.default` configuration -parameter. Alternatively, you can use the `{Execution}` annotation to change the -execution mode for the annotated element and its subelements (if any) which allows you to -activate parallel execution for individual test classes, one by one. - -[source,properties] -.Configuration parameters to execute all tests in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent ----- - -The default execution mode is applied to all nodes of the test tree with a few notable -exceptions, namely test classes that use the `Lifecycle.PER_CLASS` mode or a -`{MethodOrderer}`. In the former case, test authors have to ensure that the test class is -thread-safe; in the latter, concurrent execution might conflict with the configured -execution order. Thus, in both cases, test methods in such test classes are only executed -concurrently if the `@Execution(CONCURRENT)` annotation is present on the test class or -method. - -You can use the `@Execution` annotation to explicitly configure the execution mode for a -test class or method: - -[source,java] ----- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] ----- - -This allows test classes or methods to opt in or out of concurrent execution regardless of -the globally configured default. - -When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will -initially be sorted accordingly and scheduled in that order. However, they are not -guaranteed to be started in exactly that order since the threads they are executed on are -not controlled directly by JUnit. - -All nodes of the test tree that are configured with the `CONCURRENT` execution mode will -be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled -separately. - -In addition, you can configure the default execution mode for top-level classes by setting -the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter. By -combining both configuration parameters, you can configure classes to run in parallel but -their methods in the same thread: - -[source,properties] -.Configuration parameters to execute top-level classes in parallel but methods in same thread ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = same_thread -junit.jupiter.execution.parallel.mode.classes.default = concurrent ----- - -The opposite combination will run all methods within one class in parallel, but top-level -classes will run sequentially: - -[source,properties] -.Configuration parameters to execute top-level classes sequentially but their methods in parallel ----- -junit.jupiter.execution.parallel.enabled = true -junit.jupiter.execution.parallel.mode.default = concurrent -junit.jupiter.execution.parallel.mode.classes.default = same_thread ----- - -The following diagram illustrates how the execution of two top-level test classes `A` and -`B` with two test methods per class behaves for all four combinations of -`junit.jupiter.execution.parallel.mode.default` and -`junit.jupiter.execution.parallel.mode.classes.default` (see labels in first column). - -//// -Source: https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNqFlE1u2zAQha9CEChio7IQKfVGXfUH_QEatICyKAIBwYQaW0QkUiDHhV3X2x4gvWFPUlKUbTmpEq2kN2-GHx403HKhS-QZn81mhSqlbWvYXDopY0I3LQgqVFcq1BIUuS_mnhIIP2jTALHvQYG1tL3ywgaJpLj7rAjND6hZsteoRvb39x9GlUEoLfvltMZL9_4M77EoSGrFJhYavAm-iA0-psH3Jia0lEymLANrk4idR_tjQintS2nEYOE4WLClwfP22H7b6QeP818MPWnvOcwJ_ldPAwutxMoYVPQ_XjHOKwa8YoT3tP0EUwww-_YHmEey52IV47EKH8dDhEAnBmmKR4mnvScdeNLnMJ8MU4yHKcQ45XiGgy4e8Qbdby1LtyNbby04VdhgwTP3qnBFBuqCR6EUdsSVtmFqwWtc0DcoS6mWXk_TebQv3YL5CK1Xk_ODuDSy_CIV5gRm2DiwuL5PKJdVd9DFUV9oRbn82aElc6_uogHxuzwP0DGBvbvCtcs17tO-6vZyy_yI2QIaWW8ydva1RcVyUPbsdahYNz1L5u2a7VjsSVnst5yRG-a6--sjU1rhqSNTVM1EJetykqqXyfSRueCF2rmwYUU63yjBMzIrjPiq9XfNewlLAw3PFlBbp2IpSZvLcHN1F1jEW1DXWu89u3-YPX1X - ---- -displayMode: compact ---- - -gantt - dateFormat X - axisFormat %s - tickInterval 1 - title ↓ threads | time → - - section (same_thread, same_thread) - A.test1() :ass1, 0, 1 - A.test2() :ass2, after ass1, 2 - B.test1() :bss1, after ass2, 3 - B.test2() :bss2, after bss1, 4 - - section (same_thread, concurrent) - A.test1() :asc1, 0, 1 - A.test2() :asc2, after asc1, 2 - B.test1() :bsc1, 0, 1 - B.test2() :bsc2, after bsc1, 2 - - section (concurrent, same_thread) - A.test1() :acs1, 0, 1 - A.test2() :acs2, 0, 1 - B.test1() :bcs1, after acs1, 2 - B.test2() :bcs2, after acs2, 2 - - section (concurrent, concurrent) - A.test1() :acc1, 0, 1 - A.test2() :acc2, 0, 1 - B.test1() :bcc1, 0, 1 - B.test2() :bcc2, 0, 1 - -//// -image::writing-tests_execution_mode.svg[caption='',title='Default execution mode configuration combinations'] - -If the `junit.jupiter.execution.parallel.mode.classes.default` configuration parameter is -not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be -used instead. - -[[writing-tests-parallel-execution-config]] -==== Configuration - -[[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service - -If parallel execution is enabled, a thread pool is used behind the scenes to execute tests -concurrently. You can configure which implementation of `HierarchicalTestExecutorService` -is used be setting the `junit.jupiter.execution.parallel.config.executor-service` -configuration parameter to one of the following options: - -`fork_join_pool` (default):: -Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause -tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of -`ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the -number of concurrently executing tests to increase. To avoid this situation, please use -`worker_thread_pool`. - -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. - -[[writing-tests-parallel-execution-config-strategies]] -===== Strategies - -Properties such as the desired parallelism and the maximum pool size can be configured -using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two -implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a -`custom` strategy. - -To select a strategy, set the `junit.jupiter.execution.parallel.config.strategy` -configuration parameter to one of the following options. - -`dynamic`:: - Computes the desired parallelism based on the number of available processors/cores - multiplied by the `junit.jupiter.execution.parallel.config.dynamic.factor` - configuration parameter (defaults to `1`). - The optional `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` - configuration parameter can be used to limit the maximum number of threads. - -`fixed`:: - Uses the mandatory `junit.jupiter.execution.parallel.config.fixed.parallelism` - configuration parameter as the desired parallelism. - The optional `junit.jupiter.execution.parallel.config.fixed.max-pool-size` - configuration parameter can be used to limit the maximum number of threads. - -`custom`:: - Allows you to specify a custom `{ParallelExecutionConfigurationStrategy}` - implementation via the mandatory `junit.jupiter.execution.parallel.config.custom.class` - configuration parameter to determine the desired configuration. - -If no configuration strategy is set, JUnit Jupiter uses the `dynamic` configuration -strategy with a factor of `1`. Consequently, the desired parallelism will be equal to the -number of available processors/cores. - -.Parallelism alone does not imply maximum number of concurrent threads -NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to -execute test will not exceed the configured parallelism. For example, when using one -of the synchronization mechanisms described in the next section, the executor service -implementation may spawn additional threads to ensure execution continues with sufficient -parallelism. If you require such guarantees, it is possible to limit the maximum number of -threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` -strategies. - -[[writing-tests-parallel-execution-config-properties]] -===== Relevant properties - -The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. - -====== General - -`junit.jupiter.execution.parallel.enabled=true|false`:: - Enable/disable parallel test execution (defaults to `false`). - -`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`:: - Default execution mode of nodes in the test tree (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`:: - Default execution mode of top-level classes (defaults to `same_thread`). - -`junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: - Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). - -`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: - Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). - -====== Dynamic strategy - -`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: - Factor to be multiplied by the number of available processors/cores to determine the - desired parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number (defaults to `1.0`). - -`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`:: - Factor to be multiplied by the number of available processors/cores and the value of - `junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired - parallelism for the ```dynamic``` configuration strategy. - Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus - the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the - number of available processors/cores) - -`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Fixed strategy - -`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: - Desired parallelism for the ```fixed``` configuration strategy (no default value). Must - be a positive integer. - -`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`:: - Desired maximum pool size of the underlying fork-join pool for the ```fixed``` - configuration strategy. Must be a positive integer greater than or equal to - `junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the - value of `junit.jupiter.execution.parallel.config.fixed.parallelism`). - -`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`:: - Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed``` - configuration strategy (defaults to `true`). Only used if - `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. - -====== Custom strategy - -`junit.jupiter.execution.parallel.config.custom.class=classname`:: - Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used - for the ```custom``` configuration strategy (no default value). - -[[writing-tests-parallel-execution-synchronization]] -==== Synchronization - -In addition to controlling the execution mode using the `{Execution}` annotation, JUnit -Jupiter provides another annotation-based declarative synchronization mechanism. The -`{ResourceLock}` annotation allows you to declare that a test class or method uses a -specific shared resource that requires synchronized access to ensure reliable test -execution. The shared resource is identified by a unique name which is a `String`. The -name can be user-defined or one of the predefined constants in `{Resources}`: -`SYSTEM_PROPERTIES`, `SYSTEM_OUT`, `SYSTEM_ERR`, `LOCALE`, or `TIME_ZONE`. - -In addition to declaring these shared resources statically, the `{ResourceLock}` -annotation has a `providers` attribute that allows registering implementations of the -`{ResourceLocksProvider}` interface that can add shared resources dynamically at runtime. -Note that resources declared statically with `{ResourceLock}` annotation are combined with -resources added dynamically by `{ResourceLocksProvider}` implementations. - -If the tests in the following example were run in parallel _without_ the use of -`{ResourceLock}`, they would be _flaky_. Sometimes they would pass, and at other times they -would fail due to the inherent race condition of writing and then reading the same JVM -System Property. - -When access to shared resources is declared using the `{ResourceLock}` annotation, the -JUnit Jupiter engine uses this information to ensure that no conflicting tests are run in -parallel. This guarantee extends to lifecycle methods of a test class or method. For -example, if a test method is annotated with a `{ResourceLock}` annotation, the "lock" will -be acquired before any `@BeforeEach` methods are executed and released after all -`@AfterEach` methods have been executed. - -[NOTE] -.Running tests in isolation -==== -If most of your test classes can be run in parallel without any synchronization but you -have some test classes that need to run in isolation, you can mark the latter with the -`{Isolated}` annotation. Tests in such classes are executed sequentially without any other -tests running at the same time. -==== - -In addition to the `String` that uniquely identifies the shared resource, you may specify -an access mode. Two tests that require `READ` access to a shared resource may run in -parallel with each other but not while any other test that requires `READ_WRITE` access -to the same shared resource is running. - -[source,java] -.Declaring shared resources "statically" with `{ResourceLock}` annotation ----- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ----- - -[source,java] -.Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ----- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ----- - -Also, "static" shared resources can be declared for _direct_ child nodes via the `target` -attribute in the `{ResourceLock}` annotation, the attribute accepts a value from -the `{ResourceLockTarget}` enum. - -Specifying `target = CHILDREN` in a class-level `{ResourceLock}` annotation -has the same semantics as adding an annotation with the same `value` and `mode` -to each test method and nested test class declared in this class. - -This may improve parallelization when a test class declares a `READ` lock, -but only a few methods hold a `READ_WRITE` lock. - -Tests in the following example would run in the `SAME_THREAD` if the `{ResourceLock}` -didn't have `target = CHILDREN`. This is because the test class declares a `READ` -shared resource, but one test method holds a `READ_WRITE` lock, -which would force the `SAME_THREAD` execution mode for all the test methods. - -[source,java] -.Declaring shared resources for child nodes with `target` attribute ----- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ----- - - -[[writing-tests-built-in-extensions]] -=== Built-in Extensions - -While the JUnit team encourages reusable extensions to be packaged and maintained in -separate libraries, JUnit Jupiter includes a few user-facing extension implementations -that are considered so generally useful that users shouldn't have to add another -dependency. - -[[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension - -The built-in `{TempDirectory}` extension is used to create and clean up a temporary -directory for an individual test or all tests in a test class. It is registered by -default. To use it, annotate a non-final, unassigned field of type `java.nio.file.Path` or -`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or -`java.io.File` annotated with `@TempDir` to a test class constructor, lifecycle method, or -test method. - -For example, the following test declares a parameter annotated with `@TempDir` for a -single test method, creates and writes to a file in the temporary directory, and checks -its content. - -[source,java,indent=0] -.A test method that requires a temporary directory ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ----- - -You can inject multiple temporary directories by specifying multiple annotated parameters. - -[source,java,indent=0] -.A test method that requires multiple temporary directories ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ----- - -The following example stores a _shared_ temporary directory in a `static` field. This -allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of -the test class. For better isolation, you should use an instance field or constructor -injection so that each test method uses a separate directory. - -[source,java,indent=0] -.A test class that shares a temporary directory across test methods ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ----- - -The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either -`NEVER`, `ON_SUCCESS`, or `ALWAYS`. If the cleanup mode is set to `NEVER`, the temporary -directory will not be deleted after the test completes. If it is set to `ON_SUCCESS`, the -temporary directory will only be deleted after the test if the test completed successfully. - -The default cleanup mode is `ALWAYS`. You can use the -`junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. - -[source,java,indent=0] -.A test class with a temporary directory that doesn't get cleaned up ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ----- - -`@TempDir` supports the programmatic creation of temporary directories via the optional -`factory` attribute. This is typically used to gain control over the temporary directory -creation, like defining the parent directory or the file system that should be used. - -Factories can be created by implementing `TempDirFactory`. Implementations must provide a -no-args constructor and should not make any assumptions regarding when and how many times -they are instantiated, but they can assume that their `createTempDirectory(...)` and -`close()` methods will both be called once per instance, in this order, and from the same -thread. - -The default implementation available in Jupiter delegates directory creation to -`java.nio.file.Files::createTempDirectory` which uses the default file system and the -system's temporary directory as the parent directory. It passes `junit-` as the prefix -string of the generated directory name to help identify it as a created by JUnit. - -The following example defines a factory that uses the test name as the directory name -prefix instead of the `junit` constant value. - -[source,java,indent=0] -.A test class with a temporary directory having the test name as the directory name prefix ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ----- - -It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the -temporary directory. The following example demonstrates how to achieve that. - -[source,java,indent=0] -.A test class with a temporary directory created with the Jimfs in-memory file system ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ----- - -`@TempDir` can also be used as a <> to -reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` -annotation that can be used as a drop-in replacement for -`@TempDir(factory = JimfsTempDirFactory.class)`. - -[source,java,indent=0] -.A custom annotation meta-annotated with `@TempDir` ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ----- - -The following example demonstrates how to use the custom `@JimfsTempDir` annotation. - -[source,java,indent=0] -.A test class using the custom annotation ----- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ----- - -Meta-annotations or additional annotations on the field or parameter the `TempDir` -annotation is declared on might expose additional attributes to configure the factory. -Such annotations and related attributes can be accessed via the `AnnotatedElementContext` -parameter of the `createTempDirectory(...)` method. - -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the -`TempDirFactory` you would like to use by default. Just like for factories configured via -the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement -the `TempDirFactory` interface. The default factory will be used for all `@TempDir` -annotations unless the `factory` attribute of the annotation specifies a different factory. - -In summary, the factory for a temporary directory is determined according to the following -precedence rules: - -1. The `factory` attribute of the `@TempDir` annotation, if present -2. The default `TempDirFactory` configured via the configuration -parameter, if present -3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. - -[[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension - -The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. -It is registered by default. To use it, annotate a field in a test class with -`{AutoClose}`. - -`@AutoClose` fields may be either `static` or non-static. If the value of an `@AutoClose` -field is `null` when it is evaluated the field will be ignored, but a warning message will -be logged to inform you. - -By default, `@AutoClose` expects the value of the annotated field to implement a `close()` -method that will be invoked to close the resource. However, developers can customize the -name of the close method via the `value` attribute. For example, `@AutoClose("shutdown")` -instructs JUnit to look for a `shutdown()` method to close the resource. - -`@AutoClose` fields are inherited from superclasses. Furthermore, `@AutoClose` fields from -subclasses will be closed before `@AutoClose` fields in superclasses. - -When multiple `@AutoClose` fields exist within a given test class, the order in which the -resources are closed depends on an algorithm that is deterministic but intentionally -nonobvious. This ensures that subsequent runs of a test suite close resources in the same -order, thereby allowing for repeatable builds. - -The `AutoCloseExtension` implements the `AfterAllCallback` and -`TestInstancePreDestroyCallback` extension APIs. Consequently, a `static` `@AutoClose` -field will be closed after all tests in the current test class have completed, effectively -after `@AfterAll` methods have executed for the test class. A non-static `@AutoClose` -field will be closed before the current test class instance is destroyed. Specifically, if -the test class is configured with `@TestInstance(Lifecycle.PER_METHOD)` semantics, a -non-static `@AutoClose` field will be closed after the execution of each test method, test -factory method, or test template method. However, if the test class is configured with -`@TestInstance(Lifecycle.PER_CLASS)` semantics, a non-static `@AutoClose` field will not -be closed until the current test class instance is no longer needed, which means after -`@AfterAll` methods and after all `static` `@AutoClose` fields have been closed. - -The following example demonstrates how to annotate an instance field with `@AutoClose` so -that the resource is automatically closed after test execution. In this example, we assume -that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. - -[source,java,indent=0] -.A test class using `@AutoClose` to close a resource ----- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] ----- -<1> Annotate an instance field with `@AutoClose`. -<2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that - will be invoked after each `@Test` method. - -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions - -The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values -returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are -often used implicitly when no specific locale or time zone is chosen. Both annotations -work on the test class level and on the test method level, and are inherited from -higher-level containers. After the annotated element has been executed, the initial -default value is restored. - -[[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale - -The default `Locale` can be specified using an -{jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ----- - -Alternatively, the default `Locale` can be created using the following attributes from -which a {jdk-javadoc-base-url}/java.base/java/util/Locale.Builder.html[`Locale.Builder`] -can create an instance: - -* `language` or -* `language` and `country` or -* `language`, `country`, and `variant` - -NOTE: The variant needs to be a string which follows the -https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ----- - -Mixing language tag configuration (via the annotation's `value` attributed) and -attributed-based configuration will cause an exception to be thrown. Furthermore, a -`variant` can only be specified if `country` is also specified. Otherwise, an exception -will be thrown. - -Any method-level `@DefaultLocale` configurations will override class-level configurations. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ----- - -NOTE: A class-level configuration means that the specified locale is set before and reset -after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{LocaleProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -[[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone - -The default `TimeZone` is specified according to the -{jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] -method. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ----- - -Any method level `@DefaultTimeZone` configurations will override class level configurations: - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ----- - -NOTE: A class-level configuration means that the specified time zone is set before and -reset after each individual test in the annotated class. - -If your use case is not covered, you can implement the `{TimeZoneProvider}` interface. - -[source,java,indent=0] ----- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ----- - -NOTE: The provider implementation must have a no-args (or the default) constructor. - -===== Thread Safety - -Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable -results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are -prepared for that and tests annotated with them will never execute in parallel (thanks to -`{ResourceLock}`) to guarantee correct test results. - -However, this does not cover all possible cases. Tested code that reads or writes default -locale and time zone _independently_ of the extensions can still run in parallel to them -and may thus behave erratically when, for example, it unexpectedly reads a locale set by -the extension in another thread. Tests that cover code that reads or writes the default -locale or time zone need to be annotated with the respective annotation: - -* `{ReadsDefaultLocale}` -* `{ReadsDefaultTimeZone}` -* `{WritesDefaultLocale}` -* `{WritesDefaultTimeZone}` - -Tests annotated in this way will never execute in parallel with tests annotated with -`@DefaultLocale` or `@DefaultTimeZone`. From 4133182ad7cbd3bb8af1f16d9e74900cee6389ce Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:09 +0100 Subject: [PATCH 18/57] Migrate writing-tests sections to Antora syntax --- .../ROOT/pages/writing-tests/annotations.adoc | 10 +- .../ROOT/pages/writing-tests/assertions.adoc | 14 +- .../ROOT/pages/writing-tests/assumptions.adoc | 6 +- .../writing-tests/built-in-extensions.adoc | 47 +++-- .../pages/writing-tests/class-templates.adoc | 4 +- .../conditional-test-execution.adoc | 34 ++-- .../ROOT/pages/writing-tests/definitions.adoc | 14 +- ...njection-for-constructors-and-methods.adoc | 8 +- .../pages/writing-tests/disabling-tests.adoc | 9 +- .../pages/writing-tests/display-names.adoc | 16 +- .../pages/writing-tests/dynamic-tests.adoc | 18 +- .../writing-tests/exception-handling.adoc | 26 ++- .../ROOT/pages/writing-tests/intro.adoc | 10 +- .../pages/writing-tests/nested-tests.adoc | 10 +- .../writing-tests/parallel-execution.adoc | 31 ++-- .../parameterized-classes-and-tests.adoc | 174 +++++++++--------- .../pages/writing-tests/repeated-tests.adoc | 9 +- .../writing-tests/tagging-and-filtering.adoc | 6 +- .../test-classes-and-methods.adoc | 10 +- .../writing-tests/test-execution-order.adoc | 14 +- .../test-instance-lifecycle.adoc | 6 +- .../test-interfaces-and-default-methods.adoc | 21 +-- .../pages/writing-tests/test-templates.adoc | 4 +- .../ROOT/pages/writing-tests/timeouts.adoc | 21 +-- 24 files changed, 232 insertions(+), 290 deletions(-) diff --git a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc index 7760a11d372a..90fd500c730f 100644 --- a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc @@ -1,5 +1,4 @@ -[[writing-tests-annotations]] -=== Annotations += Annotations JUnit Jupiter supports the following annotations for configuring tests and extending the framework. @@ -126,7 +125,7 @@ WARNING: Some annotations may currently be _experimental_. Consult the table in <> for details. [[writing-tests-meta-annotations]] -==== Meta-Annotations and Composed Annotations +== Meta-Annotations and Composed Annotations JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can define your own _composed annotation_ that will automatically _inherit_ the semantics of @@ -139,7 +138,7 @@ named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for [source,java,indent=0] ---- -include::{testDir}/example/Fast.java[tags=user_guide] +include::example$java/example/Fast.java[tags=user_guide] ---- The following `@Test` method demonstrates usage of the `@Fast` annotation. @@ -158,7 +157,7 @@ that can be used as a drop-in replacement for `@Tag("fast")` _and_ `@Test`. [source,java,indent=0] ---- -include::{testDir}/example/FastTest.java[tags=user_guide] +include::example$java/example/FastTest.java[tags=user_guide] ---- JUnit automatically recognizes the following as a `@Test` method that is tagged with @@ -171,4 +170,3 @@ void myFastTest() { // ... } ---- - diff --git a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc index 71345d429bd0..6166f3597124 100644 --- a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc @@ -1,5 +1,4 @@ -[[writing-tests-assertions]] -=== Assertions += Assertions JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java lambdas. All JUnit Jupiter assertions @@ -14,7 +13,7 @@ complex or time-consuming, as it is only evaluated when the assertion fails. [source,java,indent=0] ---- -include::{testDir}/example/AssertionsDemo.java[tags=user_guide] +include::example$java/example/AssertionsDemo.java[tags=user_guide] ---- [[writing-tests-assertions-preemptive-timeouts]] @@ -40,7 +39,7 @@ Similar side effects may be encountered with other frameworks that rely on ==== [[writing-tests-assertions-kotlin]] -==== Kotlin Assertion Support +== Kotlin Assertion Support JUnit Jupiter also comes with a few assertion methods that lend themselves well to being used in https://kotlinlang.org/[Kotlin]. All JUnit Jupiter Kotlin assertions are top-level @@ -48,11 +47,11 @@ functions in the `org.junit.jupiter.api` package. [source,kotlin,indent=0] ---- -include::{kotlinTestDir}/example/KotlinAssertionsDemo.kt[tags=user_guide] +include::example$kotlin/example/KotlinAssertionsDemo.kt[tags=user_guide] ---- [[writing-tests-assertions-third-party]] -==== Third-party Assertion Libraries +== Third-party Assertion Libraries Even though the assertion facilities provided by JUnit Jupiter are sufficient for many testing scenarios, there are times when more power and additional functionality are @@ -68,7 +67,7 @@ from `org.assertj.core.api.Assertions` and then use them in tests like in the [source,java,indent=0] ---- -include::{testDir}/example/AssertJAssertionsDemo.java[tags=user_guide] +include::example$java/example/AssertJAssertionsDemo.java[tags=user_guide] ---- [TIP] @@ -96,4 +95,3 @@ analysis tool that fails the build if Jupiter's `Assertions` class is used. ---- ==== - diff --git a/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc index ccf7be42d671..59e05de54c0a 100644 --- a/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/assumptions.adoc @@ -1,5 +1,4 @@ -[[writing-tests-assumptions]] -=== Assumptions += Assumptions Assumptions are typically used whenever it does not make sense to continue execution of a given test — for example, if the test depends on something that does not exist in the @@ -19,7 +18,7 @@ All JUnit Jupiter assumptions are static methods in the `{Assumptions}` class. [source,java,indent=0] ---- -include::{testDir}/example/AssumptionsDemo.java[tags=user_guide] +include::example$java/example/AssumptionsDemo.java[tags=user_guide] ---- NOTE: It is also possible to use methods from JUnit 4's `org.junit.Assume` class for @@ -30,4 +29,3 @@ TIP: If you use AssertJ for assertions, you may also wish to use AssertJ for ass To do so, you can statically import the `assumeThat()` method from `org.assertj.core.api.Assumptions` and then use AssertJ's fluent API to specify your assumptions. - diff --git a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc index 7dfa2ee9e328..67804ac7ed65 100644 --- a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc @@ -1,5 +1,4 @@ -[[writing-tests-built-in-extensions]] -=== Built-in Extensions += Built-in Extensions While the JUnit team encourages reusable extensions to be packaged and maintained in separate libraries, JUnit Jupiter includes a few user-facing extension implementations @@ -7,7 +6,7 @@ that are considered so generally useful that users shouldn't have to add another dependency. [[writing-tests-built-in-extensions-TempDirectory]] -==== The @TempDir Extension +== The @TempDir Extension The built-in `{TempDirectory}` extension is used to create and clean up a temporary directory for an individual test or all tests in a test class. It is registered by @@ -23,7 +22,7 @@ its content. [source,java,indent=0] .A test method that requires a temporary directory ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_parameter_injection] ---- You can inject multiple temporary directories by specifying multiple annotated parameters. @@ -31,7 +30,7 @@ You can inject multiple temporary directories by specifying multiple annotated p [source,java,indent=0] .A test method that requires multiple temporary directories ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_multiple_directories] ---- The following example stores a _shared_ temporary directory in a `static` field. This @@ -42,7 +41,7 @@ injection so that each test method uses a separate directory. [source,java,indent=0] .A test class that shares a temporary directory across test methods ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_field_injection] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_field_injection] ---- The `@TempDir` annotation has an optional `cleanup` attribute that can be set to either @@ -57,7 +56,7 @@ The default cleanup mode is `ALWAYS`. You can use the [source,java,indent=0] .A test class with a temporary directory that doesn't get cleaned up ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_cleanup_mode] ---- `@TempDir` supports the programmatic creation of temporary directories via the optional @@ -81,7 +80,7 @@ prefix instead of the `junit` constant value. [source,java,indent=0] .A test class with a temporary directory having the test name as the directory name prefix ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_factory_name_prefix] ---- It is also possible to use an in-memory file system like `{Jimfs}` for the creation of the @@ -90,7 +89,7 @@ temporary directory. The following example demonstrates how to achieve that. [source,java,indent=0] .A test class with a temporary directory created with the Jimfs in-memory file system ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ---- `@TempDir` can also be used as a <> to @@ -101,7 +100,7 @@ annotation that can be used as a drop-in replacement for [source,java,indent=0] .A custom annotation meta-annotated with `@TempDir` ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation] ---- The following example demonstrates how to use the custom `@JimfsTempDir` annotation. @@ -109,7 +108,7 @@ The following example demonstrates how to use the custom `@JimfsTempDir` annotat [source,java,indent=0] .A test class using the custom annotation ---- -include::{testDir}/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] +include::example$java/example/TempDirectoryDemo.java[tags=user_guide_composed_annotation_usage] ---- Meta-annotations or additional annotations on the field or parameter the `TempDir` @@ -133,7 +132,7 @@ parameter, if present 3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. [[writing-tests-built-in-extensions-AutoClose]] -==== The @AutoClose Extension +== The @AutoClose Extension The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. It is registered by default. To use it, annotate a field in a test class with @@ -175,14 +174,14 @@ that the default `@TestInstance(Lifecycle.PER_METHOD)` semantics apply. [source,java,indent=0] .A test class using `@AutoClose` to close a resource ---- -include::{testDir}/example/AutoCloseDemo.java[tags=user_guide_example] +include::example$java/example/AutoCloseDemo.java[tags=user_guide_example] ---- <1> Annotate an instance field with `@AutoClose`. <2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that will be invoked after each `@Test` method. [[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] -==== The @DefaultLocale and @DefaultTimeZone Extensions +== The @DefaultLocale and @DefaultTimeZone Extensions The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values returned from `Locale.getDefault()` and `TimeZone.getDefault()`, respectively, which are @@ -192,14 +191,14 @@ higher-level containers. After the annotated element has been executed, the init default value is restored. [[writing-tests-built-in-extensions-DefaultLocale]] -===== @DefaultLocale +=== @DefaultLocale The default `Locale` can be specified using an {jdk-javadoc-base-url}/java.base/java/util/Locale.html#forLanguageTag-java.lang.String-[IETF BCP 47 language tag string]. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tags=default_locale_language] ---- Alternatively, the default `Locale` can be created using the following attributes from @@ -215,7 +214,7 @@ https://www.rfc-editor.org/rfc/rfc5646.html[IETF BCP 47 / RFC 5646] syntax [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_language_alternatives] ---- Mixing language tag configuration (via the annotation's `value` attributed) and @@ -227,7 +226,7 @@ Any method-level `@DefaultLocale` configurations will override class-level confi [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_class_level] ---- NOTE: A class-level configuration means that the specified locale is set before and reset @@ -237,13 +236,13 @@ If your use case is not covered, you can implement the `{LocaleProvider}` interf [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_locale_with_provider] ---- NOTE: The provider implementation must have a no-args (or the default) constructor. [[writing-tests-built-in-extensions-DefaultTimeZone]] -===== @DefaultTimeZone +=== @DefaultTimeZone The default `TimeZone` is specified according to the {jdk-javadoc-base-url}/java.base/java/util/TimeZone.html#getTimeZone(java.lang.String)[TimeZone.getTimeZone(String)] @@ -251,14 +250,14 @@ method. [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_zone] ---- Any method level `@DefaultTimeZone` configurations will override class level configurations: [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_timezone_class_level] ---- NOTE: A class-level configuration means that the specified time zone is set before and @@ -268,12 +267,12 @@ If your use case is not covered, you can implement the `{TimeZoneProvider}` inte [source,java,indent=0] ---- -include::{testDir}/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] +include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=default_time_zone_with_provider] ---- NOTE: The provider implementation must have a no-args (or the default) constructor. -===== Thread Safety +=== Thread Safety Since the default locale and time zone are global state, reading and writing them during <> can lead to unpredictable diff --git a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc index e6abf92bf6ba..9159045675f6 100644 --- a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc @@ -1,5 +1,4 @@ -[[writing-tests-class-templates]] -=== Class Templates += Class Templates A `{ClassTemplate}` is not a regular test class but rather a template for the contained test cases. As such, it is designed to be invoked multiple times depending on invocation @@ -11,4 +10,3 @@ with full support for the same lifecycle callbacks and extensions. Please refer NOTE: <> are a built-in specialization of class templates. - diff --git a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc index 068f8db579ae..ab2d5d500fa1 100644 --- a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc @@ -1,5 +1,4 @@ -[[writing-tests-conditional-execution]] -=== Conditional Test Execution += Conditional Test Execution The <> extension API in JUnit Jupiter allows developers to either _enable_ or _disable_ a test class or test method based on certain @@ -54,7 +53,7 @@ the `org.junit.jupiter.api.condition` package. ==== [[writing-tests-conditional-execution-os]] -==== Operating System and Architecture Conditions +== Operating System and Architecture Conditions A container or test may be enabled or disabled on a particular operating system, architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` @@ -64,18 +63,18 @@ annotations. [source,java,indent=0] .Conditional execution based on operating system ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ---- [[writing-tests-conditional-execution-architectures-demo]] [source,java,indent=0] .Conditional execution based on architecture ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ---- [[writing-tests-conditional-execution-jre]] -==== Java Runtime Environment Conditions +== Java Runtime Environment Conditions A container or test may be enabled or disabled on particular versions of the Java Runtime Environment (JRE) via the `{EnabledOnJre}` and `{DisabledOnJre}` annotations or on a @@ -88,7 +87,7 @@ constants. [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre] ---- Since the enum constants defined in {JRE} are static for any given JUnit release, you @@ -105,11 +104,11 @@ versions. [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ---- [[writing-tests-conditional-execution-native]] -==== Native Image Conditions +== Native Image Conditions A container or test may be enabled or disabled within a https://www.graalvm.org/reference-manual/native-image/[GraalVM native image] via the @@ -120,11 +119,11 @@ Build Tools] project. [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ---- [[writing-tests-conditional-execution-system-properties]] -==== System Property Conditions +== System Property Conditions A container or test may be enabled or disabled based on the value of the `named` JVM system property via the `{EnabledIfSystemProperty}` and `{DisabledIfSystemProperty}` @@ -133,7 +132,7 @@ regular expression. [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_system_property] ---- [TIP] @@ -145,7 +144,7 @@ present, indirectly present, or meta-present on a given element. ==== [[writing-tests-conditional-execution-environment-variables]] -==== Environment Variable Conditions +== Environment Variable Conditions A container or test may be enabled or disabled based on the value of the `named` environment variable from the underlying operating system via the @@ -154,7 +153,7 @@ value supplied via the `matches` attribute will be interpreted as a regular expr [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_environment_variable] ---- [TIP] @@ -166,7 +165,7 @@ they are directly present, indirectly present, or meta-present on a given elemen ==== [[writing-tests-conditional-execution-custom]] -==== Custom Conditions +== Custom Conditions As an alternative to implementing an <>, a container or test may be enabled or disabled based on a _condition method_ configured via @@ -178,7 +177,7 @@ The following test class demonstrates how to configure a local method named [source,java,indent=0] ---- -include::{testDir}/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] +include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_custom] ---- Alternatively, the condition method can be located outside the test class. In this case, @@ -189,7 +188,7 @@ example. ---- package example; -include::{testDir}/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] +include::example$java/example/ExternalCustomConditionDemo.java[tags=user_guide_external_custom_condition] ---- [NOTE] @@ -221,4 +220,3 @@ disable it when such support is unavailable as follows. disabledReason = "headless environment") ---- ==== - diff --git a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc index b572ec559b06..86dc2331fd19 100644 --- a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc @@ -1,17 +1,15 @@ -[[writing-tests-definitions]] -=== Definitions += Definitions + +== Platform Concepts -.Platform Concepts -**** Container:: a node in the test tree that contains other containers or tests as its children (e.g. a _test class_). Test:: a node in the test tree that verifies expected behavior when executed (e.g. a `@Test` method). -**** -.Jupiter Concepts -**** +== Jupiter Concepts + Lifecycle Method:: any method that is directly annotated or meta-annotated with `@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. @@ -27,5 +25,3 @@ any instance method that is directly annotated or meta-annotated with `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, or `@TestTemplate`. With the exception of `@Test`, these create a _container_ in the test tree that groups _tests_ or, potentially (for `@TestFactory`), other _containers_. -**** - diff --git a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc index 963d1b2f6df0..85c0b3d7ecc8 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc @@ -1,5 +1,4 @@ -[[writing-tests-dependency-injection]] -=== Dependency Injection for Constructors and Methods += Dependency Injection for Constructors and Methods In all prior JUnit versions, test constructors or methods were not allowed to have parameters (at least not with the standard `Runner` implementations). As one of the major @@ -28,7 +27,7 @@ class constructor, `@BeforeEach` method, and `@Test` method. [source,java,indent=0] ---- -include::{testDir}/example/TestInfoDemo.java[tags=user_guide] +include::example$java/example/TestInfoDemo.java[tags=user_guide] ---- * `{RepetitionExtension}`: if a method parameter in a `@RepeatedTest`, `@BeforeEach`, or @@ -52,7 +51,7 @@ them in the user interface for test results. [source,java,indent=0] ---- -include::{testDir}/example/TestReporterDemo.java[tags=user_guide] +include::example$java/example/TestReporterDemo.java[tags=user_guide] ---- NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate @@ -89,4 +88,3 @@ When the type of the parameter to inject is the only condition for your `{ParameterResolver}`, you can use the generic `{TypeBasedParameterResolver}` base class. The `supportsParameters` method is implemented behind the scenes and supports parameterized types. - diff --git a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc index cf8460955594..981acf5d408d 100644 --- a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc @@ -1,5 +1,4 @@ -[[writing-tests-disabling]] -=== Disabling Tests += Disabling Tests Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` annotation, via one of the annotations discussed in @@ -19,14 +18,14 @@ Here's a `@Disabled` test class. [source,java,indent=0] ---- -include::{testDir}/example/DisabledClassDemo.java[tags=user_guide] +include::example$java/example/DisabledClassDemo.java[tags=user_guide] ---- And here's a test class that contains a `@Disabled` test method. [source,java,indent=0] ---- -include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] +include::example$java/example/DisabledTestsDemo.java[tags=user_guide] ---- [TIP] @@ -44,5 +43,3 @@ traceability, etc. `@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. ==== - - diff --git a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc index 2346875b83a8..de76247ca321 100644 --- a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc @@ -1,5 +1,4 @@ -[[writing-tests-display-names]] -=== Display Names += Display Names Test classes and test methods can declare custom display names via `@DisplayName` -- with spaces, special characters, and even emojis -- that will be displayed in test reports and @@ -7,7 +6,7 @@ by test runners and IDEs. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameDemo.java[tags=user_guide] +include::example$java/example/DisplayNameDemo.java[tags=user_guide] ---- [NOTE] @@ -37,7 +36,7 @@ Any remaining ISO control characters in a display name will be replaced as follo ==== [[writing-tests-display-name-generator]] -==== Display Name Generators +== Display Name Generators JUnit Jupiter supports custom display name generators that can be configured via the `@DisplayNameGeneration` annotation. @@ -64,7 +63,7 @@ generator. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] +include::example$java/example/DisplayNameGeneratorDemo.java[tags=user_guide_replace_underscores] ---- Running the above test class results in the following display names. @@ -85,7 +84,7 @@ following example. [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] +include::example$java/example/DisplayNameGeneratorDemo.java[tags=user_guide_indicative_sentences] ---- Running the above test class results in the following display names. @@ -106,7 +105,7 @@ With `IndicativeSentences`, you can optionally specify custom sentence fragments [source,java,indent=0] ---- -include::{testDir}/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] +include::example$java/example/DisplayNameGeneratorDemo.java[tags=user_guide_custom_sentence_fragments] ---- Running the above test class results in the following display names. @@ -123,7 +122,7 @@ A year is a leap year ✔ [[writing-tests-display-name-generator-default]] -==== Setting the Default Display Name Generator +== Setting the Default Display Name Generator You can use the `junit.jupiter.displayname.generator.default` <> to specify the fully qualified @@ -158,4 +157,3 @@ following precedence rules: 3. by calling the default `DisplayNameGenerator` configured via the configuration parameter, if present 4. by calling `org.junit.jupiter.api.DisplayNameGenerator.Standard` - diff --git a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc index 92c3ae99ffbd..5fea6ae2737f 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc @@ -1,5 +1,4 @@ -[[writing-tests-dynamic-tests]] -=== Dynamic Tests += Dynamic Tests The standard `@Test` annotation in JUnit Jupiter described in <> is very similar to the `@Test` annotation in JUnit 4. Both @@ -48,7 +47,7 @@ or extensions between the execution of individual dynamic tests generated by the `@TestFactory` method. [[writing-tests-dynamic-tests-examples]] -==== Dynamic Test Examples +== Dynamic Test Examples The following `DynamicTestsDemo` class demonstrates several examples of test factories and dynamic tests. @@ -79,11 +78,11 @@ a nested hierarchy of dynamic tests utilizing `DynamicContainer`. [source,java] ---- -include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide] +include::example$java/example/DynamicTestsDemo.java[tags=user_guide] ---- [[writing-tests-dynamic-tests-named-support]] -==== Dynamic Tests and Named +== Dynamic Tests and Named In some cases, it can be more natural to specify inputs together with a descriptive name using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as @@ -93,11 +92,11 @@ interface along with `Named` via the `NamedExecutable` base class. [source,java] ---- -include::{testDir}/example/DynamicTestsNamedDemo.java[tags=user_guide] +include::example$java/example/DynamicTestsNamedDemo.java[tags=user_guide] ---- [[writing-tests-dynamic-tests-uri-test-source]] -==== URI Test Sources for Dynamic Tests +== URI Test Sources for Dynamic Tests The JUnit Platform provides `TestSource`, a representation of the source of a test or container used to navigate to its location by IDEs and build tools. @@ -132,7 +131,7 @@ implementations. If none of the above `TestSource` implementations are applicable. [[writing-tests-dynamic-tests-parallel-execution]] -==== Parallel Execution +== Parallel Execution Dynamic tests and containers support <>. You can configure their @@ -141,7 +140,7 @@ factory methods as illustrated by the following example. [source,java,indent=0] ---- -include::{testDir}/example/DynamicTestsDemo.java[tags=execution_mode] +include::example$java/example/DynamicTestsDemo.java[tags=execution_mode] ---- Executing the above test factory method results in the following test tree and execution @@ -154,4 +153,3 @@ modes: **** length > 0 -- `CONCURRENT` (from `executionMode(...)` call) **** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call) ** ... (same for "Container B" and "Container C") - diff --git a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc index 23d17f93f422..d71bea1c10a9 100644 --- a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc @@ -1,5 +1,4 @@ -[[writing-tests-exceptions]] -=== Exception Handling += Exception Handling JUnit Jupiter provides robust support for handling test exceptions. This includes the built-in mechanisms for managing test failures due to exceptions, the role of exceptions @@ -7,7 +6,7 @@ in implementing assertions and assumptions, and how to specifically assert non-t conditions in code. [[writing-tests-exceptions-uncaught]] -==== Uncaught Exceptions +== Uncaught Exceptions In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an extension and not caught within that test method, lifecycle method, or extension, the @@ -29,7 +28,7 @@ Jupiter will mark the test as failed. [source,java,indent=0] ---- -include::{testDir}/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] +include::example$java/example/exception/UncaughtExceptionHandlingDemo.java[tags=user_guide] ---- NOTE: It's important to note that specifying a `throws` clause in the test method has @@ -38,7 +37,7 @@ as an expectation or assertion about what exceptions the test method should thro fails only if an exception is thrown unexpectedly or if an assertion fails. [[writing-tests-exceptions-failed-assertions]] -==== Failed Assertions +== Failed Assertions Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw @@ -62,11 +61,11 @@ will mark the test as failed. [source,java,indent=0] ---- -include::{testDir}/example/exception/FailedAssertionDemo.java[tags=user_guide] +include::example$java/example/exception/FailedAssertionDemo.java[tags=user_guide] ---- [[writing-tests-exceptions-expected]] -==== Asserting Expected Exceptions +== Asserting Expected Exceptions JUnit Jupiter offers specialized assertions for testing that specific exceptions are thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly()` @@ -74,7 +73,7 @@ assertions are critical tools for validating that your code responds correctly t conditions by throwing the appropriate exceptions. [[writing-tests-exceptions-expected-assertThrows]] -===== Using `assertThrows()` +=== Using `assertThrows()` The `assertThrows()` method is used to verify that a particular type of exception is thrown during the execution of a provided executable block. It not only checks for the @@ -84,11 +83,11 @@ thrown exception object to allow performing additional assertions on it. [source,java,indent=0] ---- -include::{testDir}/example/exception/ExceptionAssertionDemo.java[tags=user_guide] +include::example$java/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ---- [[writing-tests-exceptions-expected-assertThrowsExactly]] -===== Using `assertThrowsExactly()` +=== Using `assertThrowsExactly()` The `assertThrowsExactly()` method is used when you need to assert that the exception thrown is exactly of a specific type, not allowing for subclasses of the expected @@ -98,11 +97,11 @@ returns the thrown exception object to allow performing additional assertions on [source,java,indent=0] ---- -include::{testDir}/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] +include::example$java/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ---- [[writing-tests-exceptions-not-expected]] -==== Asserting That no Exception is Expected +== Asserting That no Exception is Expected Although any exception thrown from a test method will cause the test to fail, there are certain use cases where it can be beneficial to explicitly assert that an exception is @@ -112,10 +111,9 @@ throw any exceptions. [source,java,indent=0] ---- -include::{testDir}/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] +include::example$java/example/exception/AssertDoesNotThrowExceptionDemo.java[tags=user_guide] ---- NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ has `assertThatNoException().isThrownBy(() -> ...)`. See also: <>. - diff --git a/documentation/modules/ROOT/pages/writing-tests/intro.adoc b/documentation/modules/ROOT/pages/writing-tests/intro.adoc index 1b6b9b38b953..6f7155423113 100644 --- a/documentation/modules/ROOT/pages/writing-tests/intro.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/intro.adoc @@ -1,9 +1,4 @@ -:testDir: ../../../../src/test/java -:testResourcesDir: ../../../../src/test/resources -:kotlinTestDir: ../../../../src/test/kotlin - -[[writing-tests]] -== Writing Tests += Writing Tests The following example provides a glimpse at the minimum requirements for writing a test in JUnit Jupiter. Subsequent sections of this chapter will provide further details on all @@ -12,6 +7,5 @@ available features. [source,java,indent=0] .A first test case ---- -include::{testDir}/example/MyFirstJUnitJupiterTests.java[tags=user_guide] +include::example$java/example/MyFirstJUnitJupiterTests.java[tags=user_guide] ---- - diff --git a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc index 9fa0ed86d4b9..7f1ac2e85542 100644 --- a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc @@ -1,5 +1,4 @@ -[[writing-tests-nested]] -=== Nested Tests += Nested Tests `@Nested` tests give the test writer more capabilities to express the relationship among several groups of tests. Such nested tests make use of Java's nested classes and @@ -9,7 +8,7 @@ both as source code and as a screenshot of the execution within an IDE. [source,java,indent=0] .Nested test suite for testing a stack ---- -include::{testDir}/example/TestingAStackDemo.java[tags=user_guide] +include::example$java/example/TestingAStackDemo.java[tags=user_guide] ---- When executing this example in an IDE, the test execution tree in the GUI will look @@ -31,7 +30,7 @@ classes. Nesting can be arbitrarily deep, and those inner classes are subject to lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. [[writing-tests-nested-interoperability]] -==== Interoperability +== Interoperability `@Nested` may be combined with <> in which case the nested test @@ -42,7 +41,7 @@ The following example illustrates how to combine `@Nested` with `@ParameterizedC [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedClassDemo.java[tags=nested] +include::example$java/example/ParameterizedClassDemo.java[tags=nested] ---- Executing the above test class yields the following output: @@ -70,4 +69,3 @@ FruitTests ✔ ├─ [1] duration = "PT1H" ✔ └─ [2] duration = "PT2H" ✔ .... - diff --git a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc index dba5c7e15b82..5460dfa5df82 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc @@ -1,5 +1,4 @@ -[[writing-tests-parallel-execution]] -=== Parallel Execution += Parallel Execution By default, JUnit Jupiter tests are run sequentially in a single thread; however, running tests in parallel -- for example, to speed up execution -- is available as an opt-in @@ -46,7 +45,7 @@ test class or method: [source,java] ---- -include::{testDir}/example/ExplicitExecutionModeDemo.java[tags=user_guide] +include::example$java/example/ExplicitExecutionModeDemo.java[tags=user_guide] ---- This allows test classes or methods to opt in or out of concurrent execution regardless of @@ -139,10 +138,10 @@ not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default used instead. [[writing-tests-parallel-execution-config]] -==== Configuration +== Configuration [[writing-tests-parallel-execution-config-executor-service]] -===== Executor Service +=== Executor Service If parallel execution is enabled, a thread pool is used behind the scenes to execute tests concurrently. You can configure which implementation of `HierarchicalTestExecutorService` @@ -166,7 +165,7 @@ to give it a try and provide feedback to the JUnit team so they can improve and <> this feature. [[writing-tests-parallel-execution-config-strategies]] -===== Strategies +=== Strategies Properties such as the desired parallelism and the maximum pool size can be configured using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two @@ -208,12 +207,12 @@ threads by configuring the maximum pool size of the `dynamic`, `fixed` and `cust strategies. [[writing-tests-parallel-execution-config-properties]] -===== Relevant properties +=== Relevant properties The following table lists relevant properties for configuring parallel execution. See <> for details on how to set such properties. -====== General +==== General `junit.jupiter.execution.parallel.enabled=true|false`:: Enable/disable parallel test execution (defaults to `false`). @@ -231,7 +230,7 @@ The following table lists relevant properties for configuring parallel execution `junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). -====== Dynamic strategy +==== Dynamic strategy `junit.jupiter.execution.parallel.config.dynamic.factor=decimal`:: Factor to be multiplied by the number of available processors/cores to determine the @@ -251,7 +250,7 @@ The following table lists relevant properties for configuring parallel execution configuration strategy (defaults to `true`). Only used if `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. -====== Fixed strategy +==== Fixed strategy `junit.jupiter.execution.parallel.config.fixed.parallelism=integer`:: Desired parallelism for the ```fixed``` configuration strategy (no default value). Must @@ -268,14 +267,14 @@ The following table lists relevant properties for configuring parallel execution configuration strategy (defaults to `true`). Only used if `junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`. -====== Custom strategy +==== Custom strategy `junit.jupiter.execution.parallel.config.custom.class=classname`:: Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used for the ```custom``` configuration strategy (no default value). [[writing-tests-parallel-execution-synchronization]] -==== Synchronization +== Synchronization In addition to controlling the execution mode using the `{Execution}` annotation, JUnit Jupiter provides another annotation-based declarative synchronization mechanism. The @@ -320,13 +319,13 @@ to the same shared resource is running. [source,java] .Declaring shared resources "statically" with `{ResourceLock}` annotation ---- -include::{testDir}/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] +include::example$java/example/sharedresources/StaticSharedResourcesDemo.java[tags=user_guide] ---- [source,java] .Adding shared resources "dynamically" with `{ResourceLocksProvider}` implementation ---- -include::{testDir}/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] +include::example$java/example/sharedresources/DynamicSharedResourcesDemo.java[tags=user_guide] ---- Also, "static" shared resources can be declared for _direct_ child nodes via the `target` @@ -348,7 +347,5 @@ which would force the `SAME_THREAD` execution mode for all the test methods. [source,java] .Declaring shared resources for child nodes with `target` attribute ---- -include::{testDir}/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] +include::example$java/example/sharedresources/ChildrenSharedResourcesDemo.java[tags=user_guide] ---- - - diff --git a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc index 70484f86cf21..075beac659dc 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc @@ -1,5 +1,4 @@ -[[writing-tests-parameterized-tests]] -=== Parameterized Classes and Tests += Parameterized Classes and Tests _Parameterized tests_ make it possible to run a test method multiple times with different arguments. They are declared just like regular `@Test` methods but use the @@ -25,7 +24,7 @@ annotation to specify a `String` array as the source of arguments. [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedTestDemo.java[tags=first_example] +include::example$java/example/ParameterizedTestDemo.java[tags=first_example] ---- When executing the above parameterized test method, each invocation will be reported @@ -44,7 +43,7 @@ The same `@ValueSource` annotation can be used to specify the source of argument [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedClassDemo.java[tags=first_example] +include::example$java/example/ParameterizedClassDemo.java[tags=first_example] ---- When executing the above parameterized test class, each invocation will be reported @@ -65,16 +64,16 @@ PalindromeTests ✔ .... [[writing-tests-parameterized-tests-setup]] -==== Required Setup +== Required Setup In order to use parameterized classes or tests you need to add a dependency on the `junit-jupiter-params` artifact. Please refer to <> for details. [[writing-tests-parameterized-tests-consuming-arguments]] -==== Consuming Arguments +== Consuming Arguments [[writing-tests-parameterized-tests-consuming-arguments-methods]] -===== Parameterized Tests +=== Parameterized Tests Parameterized test methods _consume_ arguments directly from the configured source (see <>) following a one-to-one correlation between @@ -97,7 +96,7 @@ _aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter ann with `{AggregateWith}`. [[writing-tests-parameterized-tests-consuming-arguments-classes]] -===== Parameterized Classes +=== Parameterized Classes Parameterized classes _consume_ arguments directly from the configured source (see <>); either via their unique constructor or via @@ -106,7 +105,7 @@ or one of its superclasses, field injection will be used. Otherwise, constructor will be used. [[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] -====== Constructor Injection +==== Constructor Injection WARNING: Constructor injection can only be used with the (default) `PER_METHOD` <> mode. Please use @@ -120,7 +119,7 @@ test class. [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedClassDemo.java[tags=constructor_injection] +include::example$java/example/ParameterizedClassDemo.java[tags=constructor_injection] ---- You may use _records_ to implement parameterized classes that avoid the boilerplate code @@ -128,11 +127,11 @@ of declaring a test class constructor. [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedRecordDemo.java[tags=example] +include::example$java/example/ParameterizedRecordDemo.java[tags=example] ---- [[writing-tests-parameterized-tests-consuming-arguments-field-injection]] -====== Field Injection +==== Field Injection For field injection, the following rules apply for fields annotated with `@Parameter`. @@ -155,7 +154,7 @@ arguments in a parameterized class. [source,java,indent=0] ---- -include::{testDir}/example/ParameterizedClassDemo.java[tags=field_injection] +include::example$java/example/ParameterizedClassDemo.java[tags=field_injection] ---- If field injection is used, no constructor parameters will be resolved with arguments from @@ -163,7 +162,7 @@ the source. Other < Initialization of the argument _before_ each invocation of the parameterized class <2> Usage of the previously initialized argument in a test method <3> Validation and cleanup of the argument _after_ each invocation of the parameterized class - diff --git a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc index c0e4eeb7544b..90e35cb9f477 100644 --- a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc @@ -1,5 +1,4 @@ -[[writing-tests-repeated-tests]] -=== Repeated Tests += Repeated Tests JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with `@RepeatedTest` and specifying the total number of repetitions @@ -64,7 +63,7 @@ developer can choose to have an instance of `{RepetitionInfo}` injected into a `@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. [[writing-tests-repeated-tests-examples]] -==== Repeated Test Examples +== Repeated Test Examples The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of repeated tests. @@ -128,7 +127,7 @@ INFO: About to execute repetition 5 of 5 for repeatedTestInGerman [source,java] ---- -include::{testDir}/example/RepeatedTestsDemo.java[tags=user_guide] +include::example$java/example/RepeatedTestsDemo.java[tags=user_guide] ---- When using the `ConsoleLauncher` with the unicode theme enabled, execution of @@ -173,5 +172,3 @@ When using the `ConsoleLauncher` with the unicode theme enabled, execution of │ ├─ Wiederholung 4 von 5 ✔ │ └─ Wiederholung 5 von 5 ✔ .... - - diff --git a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc index 5023e0971ea4..b38ffbb75bb9 100644 --- a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc @@ -1,5 +1,4 @@ -[[writing-tests-tagging-and-filtering]] -=== Tagging and Filtering += Tagging and Filtering Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be used to filter <>. Please refer to the @@ -8,9 +7,8 @@ Platform. [source,java,indent=0] ---- -include::{testDir}/example/TaggingDemo.java[tags=user_guide] +include::example$java/example/TaggingDemo.java[tags=user_guide] ---- TIP: See <> for examples demonstrating how to create custom annotations for tags. - diff --git a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc index 69ee0ea0a894..aeb1b1d552d0 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc @@ -1,5 +1,4 @@ -[[writing-tests-classes-and-methods]] -=== Test Classes and Methods += Test Classes and Methods Test methods and lifecycle methods may be declared locally within the current test class, inherited from superclasses, or inherited from interfaces (see @@ -45,7 +44,7 @@ lifecycle methods. For further information on runtime semantics, see [source,java,indent=0] .A standard Java test class ---- -include::{testDir}/example/StandardTests.java[tags=user_guide] +include::example$java/example/StandardTests.java[tags=user_guide] ---- It is also possible to use Java `record` classes as test classes as illustrated by the @@ -54,7 +53,7 @@ following example. [source,java,indent=0] .A test class written as a Java record ---- -include::{testDir}/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] +include::example$java/example/MyFirstJUnitJupiterRecordTests.java[tags=user_guide] ---- Test and lifecycle methods may be written in Kotlin and may optionally use the `suspend` @@ -63,7 +62,7 @@ keyword for testing code using coroutines. [source,kotlin] .A test class written in Kotlin ---- -include::{kotlinTestDir}/example/KotlinCoroutinesDemo.kt[tags=user_guide] +include::example$kotlin/example/KotlinCoroutinesDemo.kt[tags=user_guide] ---- NOTE: Using suspending functions as test or lifecycle methods requires @@ -72,4 +71,3 @@ https://central.sonatype.com/artifact/org.jetbrains.kotlin/kotlin-reflect[`kotli and https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core[`kotlinx-coroutines-core`] to be present on the classpath or module path. - diff --git a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc index 13150a3a2485..83b38d41fc97 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc @@ -1,5 +1,4 @@ -[[writing-tests-test-execution-order]] -=== Test Execution Order += Test Execution Order By default, test classes and methods will be ordered using an algorithm that is deterministic but intentionally nonobvious. This ensures that subsequent runs of a test @@ -9,7 +8,7 @@ repeatable builds. NOTE: See <> for a definition of _test method_ and _test class_. [[writing-tests-test-execution-order-methods]] -==== Method Order +== Method Order Although true _unit tests_ typically should not rely on the order in which they are executed, there are times when it is necessary to enforce a specific test method execution @@ -44,11 +43,11 @@ order specified via the `@Order` annotation. [source,java,indent=0] ---- -include::{testDir}/example/OrderedTestsDemo.java[tags=user_guide] +include::example$java/example/OrderedTestsDemo.java[tags=user_guide] ---- [[writing-tests-test-execution-order-methods-default]] -===== Setting the Default Method Orderer +=== Setting the Default Method Orderer You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the @@ -71,7 +70,7 @@ Similarly, you can specify the fully qualified name of any custom class that imp `MethodOrderer`. [[writing-tests-test-execution-order-classes]] -==== Class Order +== Class Order Although test classes typically should not rely on the order in which they are executed, there are times when it is desirable to enforce a specific test class execution order. You @@ -136,6 +135,5 @@ executed in the order specified via the `@Order` annotation. [source,java,indent=0] ---- -include::{testDir}/example/OrderedNestedTestClassesDemo.java[tags=user_guide] +include::example$java/example/OrderedNestedTestClassesDemo.java[tags=user_guide] ---- - diff --git a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc index b92bf55f492e..be2479032530 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc @@ -1,5 +1,4 @@ -[[writing-tests-test-instance-lifecycle]] -=== Test Instance Lifecycle += Test Instance Lifecycle In order to allow individual test methods to be executed in isolation and to avoid unexpected side effects due to mutable test instance state, JUnit creates a new instance @@ -27,7 +26,7 @@ easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as mode. [[writing-tests-test-instance-lifecycle-changing-default]] -==== Changing the Default Test Instance Lifecycle +== Changing the Default Test Instance Lifecycle If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter will use a _default_ lifecycle mode. The standard _default_ mode is `PER_METHOD`; @@ -61,4 +60,3 @@ configures "per-class" semantics as the default but tests in the IDE are execute "per-method" semantics, that can make it difficult to debug errors that occur on the build server. It is therefore recommended to change the default in the JUnit Platform configuration file instead of via a JVM system property. - diff --git a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc index 2a7468bcbcc3..81151f883771 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc @@ -1,5 +1,4 @@ -[[writing-tests-test-interfaces-and-default-methods]] -=== Test Interfaces and Default Methods += Test Interfaces and Default Methods JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFactory`, `@TestTemplate`, `@BeforeEach`, and `@AfterEach` to be declared on interface `default` @@ -10,12 +9,12 @@ annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see [source,java] ---- -include::{testDir}/example/testinterface/TestLifecycleLogger.java[tags=user_guide] +include::example$java/example/testinterface/TestLifecycleLogger.java[tags=user_guide] ---- [source,java] ---- -include::{testDir}/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] +include::example$java/example/testinterface/TestInterfaceDynamicTestsDemo.java[tags=user_guide] ---- `@ExtendWith` and `@Tag` can be declared on a test interface so that classes that @@ -25,14 +24,14 @@ implement the interface automatically inherit its tags and extensions. See [source,java] ---- -include::{testDir}/example/testinterface/TimeExecutionLogger.java[tags=user_guide] +include::example$java/example/testinterface/TimeExecutionLogger.java[tags=user_guide] ---- In your test class you can then implement these test interfaces to have them applied. [source,java] ---- -include::{testDir}/example/testinterface/TestInterfaceDemo.java[tags=user_guide] +include::example$java/example/testinterface/TestInterfaceDemo.java[tags=user_guide] ---- Running the `TestInterfaceDemo` results in output similar to the following: @@ -54,17 +53,17 @@ For example, you can write tests for how implementations of `Object.equals` or [source,java] ---- -include::{testDir}/example/defaultmethods/Testable.java[tags=user_guide] +include::example$java/example/defaultmethods/Testable.java[tags=user_guide] ---- [source,java] ---- -include::{testDir}/example/defaultmethods/EqualsContract.java[tags=user_guide] +include::example$java/example/defaultmethods/EqualsContract.java[tags=user_guide] ---- [source,java] ---- -include::{testDir}/example/defaultmethods/ComparableContract.java[tags=user_guide] +include::example$java/example/defaultmethods/ComparableContract.java[tags=user_guide] ---- In your test class you can then implement both contract interfaces thereby inheriting the @@ -72,9 +71,7 @@ corresponding tests. Of course you'll have to implement the abstract methods. [source,java] ---- -include::{testDir}/example/defaultmethods/StringTests.java[tags=user_guide] +include::example$java/example/defaultmethods/StringTests.java[tags=user_guide] ---- NOTE: The above tests are merely meant as examples and therefore not complete. - - diff --git a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc index 9c8bc506957a..9afe87e2c9be 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc @@ -1,5 +1,4 @@ -[[writing-tests-test-templates]] -=== Test Templates += Test Templates A `{TestTemplate}` method is not a regular test case but rather a template for a test case. As such, it is designed to be invoked multiple times depending on the number of @@ -12,4 +11,3 @@ method with full support for the same lifecycle callbacks and extensions. Please NOTE: <> and <> are built-in specializations of test templates. - diff --git a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc index 2cabb0284124..51fb4e18e371 100644 --- a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc @@ -1,5 +1,4 @@ -[[writing-tests-declarative-timeouts]] -=== Timeouts += Timeouts The `@Timeout` annotation allows one to declare that a test, test factory, test template, or lifecycle method should fail if its execution time exceeds a given duration. The time @@ -9,7 +8,7 @@ The following example shows how `@Timeout` is applied to lifecycle and test meth [source,java] ---- -include::{testDir}/example/TimeoutDemo.java[tags=user_guide] +include::example$java/example/TimeoutDemo.java[tags=user_guide] ---- To apply the same timeout to all test methods within a test class and all of its `@Nested` @@ -28,7 +27,7 @@ If `@Timeout` is present on a `@TestTemplate` method — for example, a `@Repeat `@ParameterizedTest` — each invocation will have the given timeout applied to it. [[writing-tests-declarative-timeouts-thread-mode]] -==== Thread mode +== Thread mode The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, `SEPARATE_THREAD`, or `INFERRED`. @@ -49,7 +48,7 @@ provided configuration parameter is invalid or not present then `SAME_THREAD` is fallback. [[writing-tests-declarative-timeouts-default-timeouts]] -==== Default Timeouts +== Default Timeouts The following <> can be used to specify default timeouts for all methods of a certain category unless they or an enclosing @@ -102,7 +101,7 @@ omitted. Specifying no unit is equivalent to using seconds. [[writing-tests-declarative-timeouts-polling]] -==== Using @Timeout for Polling Tests +== Using @Timeout for Polling Tests When dealing with asynchronous code, it is common to write tests that poll while waiting for something to happen before performing any assertions. In some cases you can rewrite @@ -120,7 +119,7 @@ until" logic very easily. [source,java] ---- -include::{testDir}/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] +include::example$java/example/PollingTimeoutDemo.java[tags=user_guide,indent=0] ---- NOTE: If you need more control over polling intervals and greater flexibility with @@ -129,7 +128,7 @@ link:https://github.com/awaitility/awaitility[Awaitility]. [[writing-tests-declarative-timeouts-debugging]] -==== Debugging Timeouts +== Debugging Timeouts Registered <> extensions are called prior to invoking `Thread.interrupt()` on the thread that is executing the timed out method. This allows to @@ -138,7 +137,7 @@ diagnosing the cause of a timeout. [[writing-tests-declarative-timeouts-debugging-thread-dump]] -===== Thread Dump on Timeout +=== Thread Dump on Timeout JUnit registers a default implementation of the <> extension point that dumps the stacks of all threads to `System.out` if enabled by setting @@ -147,7 +146,7 @@ the `junit.jupiter.execution.timeout.threaddump.enabled` [[writing-tests-declarative-timeouts-mode]] -==== Disable @Timeout Globally +== Disable @Timeout Globally When stepping through your code in a debug session, a fixed timeout limit may influence the result of the test, e.g. mark the test as failed although all assertions were met. @@ -158,5 +157,3 @@ and `disabled_on_debug`. The default mode is `enabled`. A VM runtime is considered to run in debug mode when one of its input parameters starts with `-agentlib:jdwp` or `-Xrunjdwp`. This heuristic is queried by the `disabled_on_debug` mode. - - From b6185b478fc85a11116ebafe58c54c854d8552e5 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:09 +0100 Subject: [PATCH 19/57] Add writing-tests sections to navigation --- documentation/modules/ROOT/nav.adoc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 1daff8e619ee..aa54c0dd07b0 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -1 +1,25 @@ * xref:overview.adoc[] +* xref:writing-tests/intro.adoc[] +** xref:writing-tests/annotations.adoc[] +** xref:writing-tests/definitions.adoc[] +** xref:writing-tests/test-classes-and-methods.adoc[] +** xref:writing-tests/display-names.adoc[] +** xref:writing-tests/assertions.adoc[] +** xref:writing-tests/assumptions.adoc[] +** xref:writing-tests/exception-handling.adoc[] +** xref:writing-tests/disabling-tests.adoc[] +** xref:writing-tests/conditional-test-execution.adoc[] +** xref:writing-tests/tagging-and-filtering.adoc[] +** xref:writing-tests/test-execution-order.adoc[] +** xref:writing-tests/test-instance-lifecycle.adoc[] +** xref:writing-tests/nested-tests.adoc[] +** xref:writing-tests/dependency-injection-for-constructors-and-methods.adoc[] +** xref:writing-tests/test-interfaces-and-default-methods.adoc[] +** xref:writing-tests/repeated-tests.adoc[] +** xref:writing-tests/parameterized-classes-and-tests.adoc[] +** xref:writing-tests/class-templates.adoc[] +** xref:writing-tests/test-templates.adoc[] +** xref:writing-tests/dynamic-tests.adoc[] +** xref:writing-tests/timeouts.adoc[] +** xref:writing-tests/parallel-execution.adoc[] +** xref:writing-tests/built-in-extensions.adoc[] From 7b6e4d60b7f807fde5c6cc0671c5e54d70e1dbe3 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:10 +0100 Subject: [PATCH 20/57] Move migrating-from-junit4.adoc to Antora module --- .../ROOT/pages/migrating-from-junit4.adoc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide/migration-from-junit4.adoc => modules/ROOT/pages/migrating-from-junit4.adoc} (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/migration-from-junit4.adoc b/documentation/modules/ROOT/pages/migrating-from-junit4.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/migration-from-junit4.adoc rename to documentation/modules/ROOT/pages/migrating-from-junit4.adoc From cb87b3158b43d13eedcd252ed6e587496e9259c2 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:10 +0100 Subject: [PATCH 21/57] Migrate migrating-from-junit4.adoc to Antora syntax --- .../ROOT/pages/migrating-from-junit4.adoc | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/documentation/modules/ROOT/pages/migrating-from-junit4.adoc b/documentation/modules/ROOT/pages/migrating-from-junit4.adoc index 099b875bdd12..b0442759aad1 100644 --- a/documentation/modules/ROOT/pages/migrating-from-junit4.adoc +++ b/documentation/modules/ROOT/pages/migrating-from-junit4.adoc @@ -1,7 +1,4 @@ -:testDir: ../../../../src/test/java - -[[migrating-from-junit4]] -== Migrating from JUnit 4 += Migrating from JUnit 4 Although the JUnit Jupiter programming model and extension model do not support JUnit 4 features such as `Rules` and `Runners` natively, it is not expected that source code @@ -17,7 +14,7 @@ classpath does not lead to any conflicts. It is therefore safe to maintain exist [[migrating-from-junit4-running]] -=== Running JUnit 4 Tests on the JUnit Platform +== Running JUnit 4 Tests on the JUnit Platform [WARNING] ==== @@ -40,7 +37,7 @@ See the example projects in the {junit-examples-repo}[`junit-examples`] reposito find out how this is done with Gradle and Maven. [[migrating-from-junit4-categories-support]] -==== Categories Support +=== Categories Support For test classes or methods that are annotated with `@Category`, the _JUnit Vintage test engine_ exposes the category's fully qualified class name as a <> @@ -50,7 +47,7 @@ Similar to the `Categories` runner in JUnit 4, this information can be used to f discovered tests before executing them (see <> for details). [[migrating-from-junit4-parallel-execution]] -=== Parallel Execution +== Parallel Execution The JUnit Vintage test engine supports parallel execution of top-level test classes and test methods, allowing existing JUnit 3 and JUnit 4 tests to benefit from improved performance through @@ -72,7 +69,7 @@ concurrent test execution. It can be enabled and configured using the following number of available processors is used. [[migrating-from-junit4-parallel-execution-class-level]] -==== Parallelization at Class Level +=== Parallelization at Class Level Let's assume we have two test classes `FooTest` and `BarTest` with each class containing three unit tests. Now, let's enable parallel execution of test classes: @@ -97,7 +94,7 @@ ForkJoinPool-1-worker-2 - FooTest::test3 ---- [[migrating-from-junit4-parallel-execution-method-level]] -==== Parallelization at Method Level +=== Parallelization at Method Level Alternatively, we can enable parallel test execution at a method level, rather than the class level: @@ -123,7 +120,7 @@ ForkJoinPool-1-worker-1 - FooTest::test3 ---- [[migrating-from-junit4-parallel-execution-class-and-method-level]] -==== Full Parallelization +=== Full Parallelization Finally, we can also enable parallelization at both class and method level: @@ -148,7 +145,7 @@ ForkJoinPool-1-worker-4 - BarTest::test1 ---- [[migrating-from-junit4-parallel-execution-pool-size]] -==== Configuring the Pool Size +=== Configuring the Pool Size The default thread pool size is equal to the number of available processors. However, we can also configure the pool size explicitly: @@ -180,7 +177,7 @@ used in this case. This happens because the pool adjusts the number of active th based on workload and system needs. [[migrating-from-junit4-parallel-execution-disabled]] -==== Sequential Execution +=== Sequential Execution On the other hand, if we disable parallel execution, the `VintageTestEngine` will execute all tests sequentially, regardless of the other properties: @@ -196,7 +193,7 @@ Similarly, tests will be executed sequentially if you enable parallel execution but enable neither class-level nor method-level parallelization. [[migrating-from-junit4-tips]] -=== Migration Tips +== Migration Tips The following are topics that you should be aware of when migrating existing JUnit 4 tests to JUnit Jupiter. @@ -232,7 +229,7 @@ tests to JUnit Jupiter. - See <> for details. [[migrating-from-junit4-tips-parameterized]] -==== Parameterized test classes +=== Parameterized test classes Unless `@UseParametersRunnerFactory` is used, a JUnit 4 parameterized test class can be converted into a JUnit Jupiter @@ -254,18 +251,18 @@ converted into a JUnit Jupiter [source,java,indent=0] .Before ---- -include::{testDir}/example/ParameterizedMigrationDemo.java[tags=before] +include::example$java/example/ParameterizedMigrationDemo.java[tags=before] ---- [source,java,indent=0] .After ---- -include::{testDir}/example/ParameterizedMigrationDemo.java[tags=after] +include::example$java/example/ParameterizedMigrationDemo.java[tags=after] ---- ==== [[migrating-from-junit4-rule-support]] -=== Limited JUnit 4 Rule Support +== Limited JUnit 4 Rule Support WARNING: _JUnit 4 rule support_ is deprecated for removal since version 6.0.0. Please migrate to the corresponding APIs and extensions provided by JUnit Jupiter. @@ -302,7 +299,7 @@ extension model of JUnit Jupiter instead of the rule-based model of JUnit 4. [[migrating-from-junit4-ignore-annotation-support]] -=== JUnit 4 @Ignore Support +== JUnit 4 @Ignore Support WARNING: _JUnit 4 `@Ignore` support_ is deprecated for removal since version 6.0.0. Please use JUnit Jupiter's `@Disabled` annotation instead. @@ -321,12 +318,12 @@ automatically registers the `IgnoreCondition` along with [source,java,indent=0] ---- -include::{testDir}/example/IgnoredTestsDemo.java[tags=user_guide] +include::example$java/example/IgnoredTestsDemo.java[tags=user_guide] ---- [[migrating-from-junit4-failure-message-arguments]] -=== Failure Message Arguments +== Failure Message Arguments The `Assumptions` and `Assertions` classes in JUnit Jupiter declare arguments in a different order than in JUnit 4. In JUnit 4 assertion and assumption methods accept the From ba9bc1cbf82912a56a2c1fd36e3ed8617ffeb5cd Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:10 +0100 Subject: [PATCH 22/57] Add migrating-from-junit4.adoc to navigation --- documentation/modules/ROOT/nav.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index aa54c0dd07b0..96c84890418b 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -23,3 +23,4 @@ ** xref:writing-tests/timeouts.adoc[] ** xref:writing-tests/parallel-execution.adoc[] ** xref:writing-tests/built-in-extensions.adoc[] +* xref:migrating-from-junit4.adoc[] From 4b21791dd3429080d7e4bc1f6726d6bd4848ecd9 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:11 +0100 Subject: [PATCH 23/57] Move running-tests.adoc to Antora module --- .../pages/running-tests/build-support.adoc} | 0 .../capturing-standard-output-error.adoc | 1216 +++++++++++++++++ .../configuration-parameters.adoc | 1216 +++++++++++++++++ .../pages/running-tests/console-launcher.adoc | 1216 +++++++++++++++++ .../pages/running-tests/discovery-issues.adoc | 1216 +++++++++++++++++ .../running-tests/discovery-selectors.adoc | 1216 +++++++++++++++++ .../ROOT/pages/running-tests/ide-support.adoc | 1216 +++++++++++++++++ .../ROOT/pages/running-tests/intro.adoc | 1216 +++++++++++++++++ .../pages/running-tests/source-launcher.adoc | 1216 +++++++++++++++++ .../running-tests/stack-trace-pruning.adoc | 1216 +++++++++++++++++ .../ROOT/pages/running-tests/tags.adoc | 1216 +++++++++++++++++ .../using-listeners-and-interceptors.adoc | 1216 +++++++++++++++++ 12 files changed, 13376 insertions(+) rename documentation/{src/docs/asciidoc/user-guide/running-tests.adoc => modules/ROOT/pages/running-tests/build-support.adoc} (100%) create mode 100644 documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/console-launcher.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/ide-support.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/intro.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/source-launcher.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/tags.adoc create mode 100644 documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/running-tests.adoc b/documentation/modules/ROOT/pages/running-tests/build-support.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/running-tests.adoc rename to documentation/modules/ROOT/pages/running-tests/build-support.adoc diff --git a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/intro.adoc b/documentation/modules/ROOT/pages/running-tests/intro.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/intro.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/tags.adoc b/documentation/modules/ROOT/pages/running-tests/tags.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/tags.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc new file mode 100644 index 000000000000..3099a146c2b4 --- /dev/null +++ b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc @@ -0,0 +1,1216 @@ +[[running-tests]] +== Running Tests + +[[running-tests-ide]] +=== IDE Support + +[[running-tests-ide-intellij-idea]] +==== IntelliJ IDEA + +IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more +information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, +however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of +IDEA download the following JARs automatically based on the API version used in the +project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. + +In order to use a different JUnit version (e.g., {version}), you may need to +include the corresponding versions of the `junit-platform-launcher`, +`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. + +.Additional Gradle Dependencies +[source,groovy] +[subs=attributes+] +---- +testImplementation(platform("org.junit:junit-bom:{version}")) +testRuntimeOnly("org.junit.platform:junit-platform-launcher") +testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +testRuntimeOnly("org.junit.vintage:junit-vintage-engine") +---- + +.Additional Maven Dependencies +[source,xml] +[subs=attributes+] +---- + + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +[[running-tests-ide-eclipse]] +==== Eclipse + +Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) +release. + +For more information on using JUnit Platform in Eclipse consult the official _Eclipse +support for JUnit 5_ section of the +https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a +(4.7.1a) - New and Noteworthy] documentation. + +[[running-tests-ide-netbeans]] +==== NetBeans + +NetBeans offers support for JUnit Jupiter and the JUnit Platform since the +https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. + +For more information consult the JUnit 5 section of the +https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 +release notes]. + +[[running-tests-ide-vscode]] +==== Visual Studio Code + +https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit +Platform via the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test +Runner] extension which is installed by default as part of the +https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java +Extension Pack]. + +For more information consult the _Testing_ section of the +https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] +documentation. + +[[running-tests-ide-other]] +==== Other IDEs + +If you are using an editor or IDE other than one of those listed in the previous sections, +and it doesn't support running tests on the JUnit Platform, you can use the +<> to run them from the command line. + +[[running-tests-build]] +=== Build Support + +[[running-tests-build-gradle]] +==== Gradle + +Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides +https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] +for executing tests on the JUnit Platform. To enable it, you need to specify +`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform() +} +---- + +Filtering by <>, +<>, or engines is also supported: + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + useJUnitPlatform { + includeTags("fast", "smoke & feature-a") + // excludeTags("slow", "ci") + includeEngines("junit-jupiter") + // excludeEngines("junit-vintage") + } +} +---- + +Please refer to the +https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] +for a comprehensive list of options. + +[[running-tests-build-gradle-bom]] +===== Aligning dependency versions + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Explicit platform dependency on the BOM +---- +dependencies { + testImplementation(platform("org.junit:junit-bom:{version}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +Since all JUnit artifacts declare a +https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, +you usually don't need to declare an explicit dependency on it yourself. Instead, it's +sufficient to declare _one_ regular dependency that includes a version number. Gradle will +then pull in the BOM automatically so you can omit the version for all other JUnit +artifacts. + +[source,groovy,indent=0] +[subs=attributes+] +.Implicit platform dependency on the BOM +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> + testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> +} +---- +<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. +<2> Dependency declaration without version. The version is supplied by the `junit-bom`. + +[WARNING] +.Declaring a dependency on junit-platform-launcher +==== +Even though pre-8.0 versions of Gradle don't require declaring an explicit +dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions +of JUnit artifacts on the test runtime classpath are aligned. + +Moreover, doing so is recommended and in some cases even required when importing the +project into an IDE like <> or +<>. +==== + +[[running-tests-build-gradle-engines-configure]] +===== Configuring Test Engines + +In order to run any tests at all, a `TestEngine` implementation must be on the classpath. + +To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency +on the dependency-aggregating JUnit Jupiter artifact similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +Alternatively, you can use Gradle's +https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] +support. + +[source,kotlin,indent=0] +[subs=attributes+] +.Kotlin DSL +---- +testing { + suites { + named("test") { + useJUnitJupiter("{version}") + } + } +} +---- + +[source,groovy,indent=0] +[subs=attributes+] +.Groovy DSL +---- +testing { + suites { + test { + useJUnitJupiter("{version}") + } + } +} +---- + +The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` +dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` +implementation similar to the following. + +[source,groovy,indent=0] +[subs=attributes+] +---- +dependencies { + testImplementation("junit:junit:{junit4-version}") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} +---- + +[[running-tests-build-gradle-config-params]] +===== Configuration Parameters + +The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit +Platform <> to influence test +discovery and execution. However, you can provide configuration parameters within the +build script via system properties (as shown below) or via the +`junit-platform.properties` file. + +[source,groovy,indent=0] +---- +test { + // ... + systemProperty("junit.jupiter.conditions.deactivate", "*") + systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") + // ... +} +---- + +[[running-tests-build-gradle-logging]] +===== Configuring Logging (optional) + +JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to +emit warnings and debug information. Please refer to the official documentation of +`{LogManager}` for configuration options. + +Alternatively, it's possible to redirect log messages to other logging frameworks such as +{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of +`{LogManager}`, set the `java.util.logging.manager` system property to the _fully +qualified class name_ of the `{LogManager}` implementation to use. The example below +demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for +details). + +[source,groovy,indent=0] +[subs=attributes+] +---- +test { + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) + systemProperty("log4j2.disableJmx", "true") +} +---- + +Other logging frameworks provide different means to redirect messages logged using +`java.util.logging`. For example, for {Logback} you can use the +https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a +dependency to the test runtime classpath. + +[[running-tests-build-maven]] +==== Maven + +Maven Surefire and Maven Failsafe provide +https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] +for executing tests on the JUnit Platform. The `pom.xml` file in the +`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin +and can serve as a starting point for configuring your Maven build. + +[WARNING] +.Minimum required version of Maven Surefire/Failsafe +==== +As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. +==== + +[[running-tests-build-maven-bom]] +===== Aligning dependency versions + +Unless you're using Spring Boot which defines its own way of managing dependencies, it is +recommended to use the JUnit Platform <> to align the +versions of all JUnit artifacts. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + org.junit + junit-bom + {version} + pom + import + + + +---- + +Using the BOM allows you to omit the version when declaring dependencies on all artifacts +with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. + +TIP: See <> for details on how to override the version +of JUnit used in your Spring Boot application. + +[[running-tests-build-maven-engines-configure]] +===== Configuring Test Engines + +In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one +`TestEngine` implementation must be added to the test classpath. + +To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies +on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the +following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + org.junit.jupiter + junit-jupiter + {version} + test + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as +long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage +`TestEngine` implementation similar to the following. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + junit + junit + {junit4-version} + test + + + org.junit.vintage + junit-vintage-engine + {version} + test + + + + + + + + maven-surefire-plugin + {surefire-version} + + + maven-failsafe-plugin + {surefire-version} + + + + +---- + +[[running-tests-build-maven-filter-test-class-names]] +===== Filtering by Test Class Names + +The Maven Surefire Plugin will scan for test classes whose fully qualified names match +the following patterns. + +- `+++**/Test*.java+++` +- `+++**/*Test.java+++` +- `+++**/*Tests.java+++` +- `+++**/*TestCase.java+++` + +Moreover, it will exclude all nested classes (including static member classes) by default. + +Note, however, that you can override this default behavior by configuring explicit +`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire +from excluding static member classes, you can override its exclude rules as follows. + +[source,xml,indent=0] +[subs=attributes+] +.Overriding exclude rules of Maven Surefire +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + + + + + + +---- + +Please see the +https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] +documentation for Maven Surefire for details. + +[[running-tests-build-maven-filter-tags]] +===== Filtering by Tags + +You can filter tests by <> or +<> using the following configuration +properties. + +- to include _tags_ or _tag expressions_, use `groups`. +- to exclude _tags_ or _tag expressions_, use `excludedGroups`. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + acceptance | !feature-a + integration, regression + + + + + +---- + +[[running-tests-build-maven-config-params]] +===== Configuration Parameters + +You can set JUnit Platform <> to +influence test discovery and execution by declaring the `configurationParameters` +property and providing key-value pairs using the Java `Properties` file syntax (as shown +below) or via the `junit-platform.properties` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + + + + maven-surefire-plugin + {surefire-version} + + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + + + + + + + +---- + +[[running-tests-build-ant]] +==== Ant + +Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that +provides native support for launching tests on the JUnit Platform. The `junitlauncher` +task is solely responsible for launching the JUnit Platform and passing it the selected +collection of tests. The JUnit Platform then delegates to registered test engines to +discover and execute the tests. + +The `junitlauncher` task attempts to align as closely as possible with native Ant +constructs such as +link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] +for allowing users to select the tests that they want executed by test engines. This gives +the task a consistent and natural feel when compared to many other core Ant tasks. + +Starting with version `1.10.6` of Ant, the `junitlauncher` task supports +link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. + +The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use +the task and can serve as a starting point. + +===== Basic Usage + +The following example demonstrates how to configure the `junitlauncher` task to select a +single test class (i.e., `com.example.project.CalculatorTests`). + +[source,xml,indent=0] +---- + + + + + + + + + + + +---- + +The `test` element allows you to specify a single test class that you want to be selected +and executed. The `classpath` element allows you to specify the classpath to be used to +launch the JUnit Platform. This classpath will also be used to locate test classes that +are part of the execution. + +The following example demonstrates how to configure the `junitlauncher` task to select +test classes from multiple locations. + +[source,xml,indent=0] +---- + + + + + + + + + + + + + + + + +---- + +In the above example, the `testclasses` element allows you to select multiple test +classes that reside in different locations. + +For further details on usage and configuration options please refer to the official Ant +documentation for the +link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. + +[[running-tests-build-spring-boot]] +==== Spring Boot + +link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for +managing the version of JUnit used in your project. In addition, the +`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit +Jupiter, AssertJ, Mockito, etc. + +If your build relies on dependency management support from Spring Boot, you should not +import JUnit's <> in your build script since that would +result in duplicate (and potentially conflicting) management of JUnit dependencies. + +If you need to override the version of a dependency used in your Spring Boot application, +you have to override the exact name of the +link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] +defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit +Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for +changing a dependency version is documented for both +link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] +and +link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. + +With Gradle you can override the JUnit Jupiter version by including the following in your +`build.gradle` file. + +[source,groovy,indent=0] +[subs=attributes+] +---- + ext['junit-jupiter.version'] = '{version}' +---- + +With Maven you can override the JUnit Jupiter version by including the following in your +`pom.xml` file. + +[source,xml,indent=0] +[subs=attributes+] +---- + + {version} + +---- + +[[running-tests-console-launcher]] +=== Console Launcher + +The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit +Platform from the console. For example, it can be used to run JUnit Vintage and JUnit +Jupiter tests and print test execution results to the console. + +An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that +contains the contents of all of its dependencies is published in the {Maven_Central} +repository under the +https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] +directory. It contains the contents of the following artifacts: + +include::{standaloneConsoleLauncherShadowedArtifactsFile}[] + +[NOTE] +==== +Since the `junit-platform-console-standalone` JAR contains the contents of all of its +dependencies, its Maven POM does not declare any dependencies. + +Furthermore, it is not very likely that you would need to include a dependency on the +`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build +script. On the contrary, the executable `junit-platform-console-standalone` JAR is +typically invoked directly from the command line or a shell script without a build script. + +If you need to declare dependencies in your build script on some of the artifacts +contained in the `junit-platform-console-standalone` artifact, you should declare +dependencies only on the JUnit artifacts that are used in your project. To simplify +dependency management of JUnit artifacts in your build, you may wish to use the +`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +details. +==== + +You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the +standalone `ConsoleLauncher` as shown below. + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar execute + +├─ JUnit Vintage +│ └─ example.JUnit4Tests +│ └─ standardJUnit4Test ✔ +└─ JUnit Jupiter + ├─ StandardTests + │ ├─ succeedingTest() ✔ + │ └─ skippedTest() ↷ for demonstration purposes + └─ A special test case + ├─ Custom test name containing spaces ✔ + ├─ ╯°□°)╯ ✔ + └─ 😱 ✔ + +Test run finished after 64 ms +[ 5 containers found ] +[ 0 containers skipped ] +[ 5 containers started ] +[ 0 containers aborted ] +[ 5 containers successful ] +[ 0 containers failed ] +[ 6 tests found ] +[ 1 tests skipped ] +[ 5 tests started ] +[ 0 tests aborted ] +[ 5 tests successful ] +[ 0 tests failed ] +---- + +You can also run the standalone `ConsoleLauncher` as shown below (for example, to include +all jars in a directory): + +[source,console,subs=attributes+] +---- +$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher +---- + +[[running-tests-console-launcher-options]] +==== Subcommands and Options + +The `{ConsoleLauncher}` provides the following subcommands: + +---- +include::{consoleLauncherOptionsFile}[] +---- + +[[running-tests-console-launcher-options-discovering-tests]] +===== Discovering tests + +---- +include::{consoleLauncherDiscoverOptionsFile}[] +---- + +[[running-tests-console-launcher-options-executing-tests]] +===== Executing tests + +.Exit Code +NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. +All non-zero codes indicate an error of some sort. For example, status code `1` +is returned if any containers or tests failed. If no tests are discovered and the +`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits +with a status code of `2`. Unexpected or invalid user input yields a status code +of `3`. An exit code of `-1` indicates an unspecified error condition. + +---- +include::{consoleLauncherExecuteOptionsFile}[] +---- + +[[running-tests-console-launcher-options-listing-test-engines]] +===== Listing test engines + +---- +include::{consoleLauncherEnginesOptionsFile}[] +---- + +[[running-tests-console-launcher-argument-files]] +==== Argument Files (@-files) + +On some platforms you may run into system limitations on the length of a command line when +creating a command line with lots of options or with long arguments. + +The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files +are files that themselves contain arguments to be passed to the command. When the +underlying https://github.com/remkop/picocli[picocli] command line parser encounters an +argument beginning with the character `@`, it expands the contents of that file into the +argument list. + +The arguments within a file can be separated by spaces or newlines. If an argument +contains embedded whitespace, the whole argument should be wrapped in double or single +quotes -- for example, `"-f=My Files/Stuff.java"`. + +If the argument file does not exist or cannot be read, the argument will be treated +literally and will not be removed. This will likely result in an "unmatched argument" +error message. You can troubleshoot such errors by executing the command with the +`picocli.trace` system property set to `DEBUG`. + +Multiple _@-files_ may be specified on the command line. The specified path may be +relative to the current directory or absolute. + +You can pass a real parameter with an initial `@` character by escaping it with an +additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be +subject to expansion. + +[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +==== Redirecting Standard Output/Error to Files + +You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to +files using the `--redirect-stdout` and `--redirect-stderr` options: + +[source,console,subs=attributes+] +---- +$ java -jar junit-platform-console-standalone-{version}.jar \ + --redirect-stdout=stdout.txt \ + --redirect-stderr=stderr.txt +---- + +[NOTE] +==== +If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both +output streams will be redirected to that file. + +The default charset is used for writing to the files. +==== + +[[running-tests-console-launcher-color-customization]] +==== Color Customization + +The colors used in the output of the `{ConsoleLauncher}` can be customized. +The option `--single-color` will apply a built-in monochrome style, while +`--color-palette` will accept a properties file to override the +https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. +The properties file below demonstrates the default style: + +[source,properties,indent=0] +---- +SUCCESSFUL = 32 +ABORTED = 33 +FAILED = 31 +SKIPPED = 35 +CONTAINER = 35 +TEST = 34 +DYNAMIC = 35 +REPORTED = 37 +---- + +[[running-tests-source-launcher]] +=== Source Launcher + +Starting with Java 25 it is possible to write minimal source code test programs +using the `org.junit.start` module. For example, like in a `HelloTests.java` +file reading: + +```java +import module org.junit.start; + +void main() { + JUnit.run(); +} + +@Test +void stringLength() { + Assertions.assertEquals(11, "Hello JUnit".length()); +} +``` +With all required modular JAR files available in a local `lib/` directory, the +following Java 25+ command will discover and execute tests using the JUnit Platform. +It will also print the result tree to the console. + +```shell +java --module-path lib --add-modules org.junit.start HelloTests.java +╷ +└─ JUnit Jupiter ✔ + └─ HelloTests ✔ + └─ stringLength() ✔ +``` + +Find JUnit's class API documentation here: {JUnit} + +[[running-tests-discovery-selectors]] +=== Discovery Selectors + +The JUnit Platform provides a rich set of discovery selectors that can be used to specify +which tests should be discovered or executed. + +Discovery selectors can be created programmatically using the factory methods in the +`{DiscoverySelectors}` class, specified declaratively via annotations when using the +<>, via options of the <>, or +generically as strings via their identifiers. + +The following discovery selectors are provided out of the box: + +|=== +| Java Type | API | Annotation | Console Launcher | Identifier + +| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` +| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` +| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` +| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` +| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` +| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` +| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` +| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` +| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` +| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` +| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` +| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` +| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` +|=== + + +[[running-tests-config-params]] +=== Configuration Parameters + +In addition to instructing the platform which test classes and test engines to include, +which packages to scan, etc., it is sometimes necessary to provide additional custom +configuration parameters that are specific to a particular test engine, listener, or +registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration +parameters_ for the following use cases. + +- <> +- <> +- <> +- <> + +_Configuration Parameters_ are text-based key-value pairs that can be supplied to test +engines running on the JUnit Platform via one of the following mechanisms. + +1. The `configurationParameter()` and `configurationParameters()` methods in + `LauncherDiscoveryRequestBuilder` which + is used to build a request supplied to the <>. + + + When running tests via one of the tools provided by the JUnit Platform you can specify + configuration parameters as follows: + * <>: use the `--config` command-line + option. + * <>: use the `systemProperty` or + `systemProperties` DSL. + * <>: use the + `configurationParameters` property. +2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + + + When running tests via the <> you can + specify custom configuration files using the `--config-resource` command-line option. +3. JVM system properties. +4. The JUnit Platform default configuration file: a file named `junit-platform.properties` + in the root of the class path that follows the syntax rules for Java `Properties` + files. + +NOTE: Configuration parameters are looked up in the exact order defined above. +Consequently, configuration parameters supplied directly to the `Launcher` take +precedence over those supplied via custom configuration files, system properties, and the +default configuration file. Similarly, configuration parameters supplied via system +properties take precedence over those supplied via the default configuration file. + +[[running-tests-config-params-deactivation-pattern]] +==== Pattern Matching Syntax + +This section describes the pattern matching syntax that is applied to the _configuration +parameters_ used for the following features. + +- <> +- <> +- <> +- <> + +If the value for the given _configuration parameter_ consists solely of an asterisk +(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value +will be treated as a comma-separated list of patterns where each pattern will be matched +against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in +a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk +(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a +pattern will be matched one-to-one against a FQCN. + +Examples: + +- `+++*+++`: matches all candidate classes. +- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and + any of its subpackages. +- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly + `MyCustomImpl`. +- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. +- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains + `System` or `Unit`. +- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly + `org.example.MyCustomImpl`. +- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose + FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. + +[[running-tests-tags]] +=== Tags + +Tags are a JUnit Platform concept for marking and filtering tests. The programming model +for adding tags to containers and tests is defined by the testing framework. For example, +in JUnit Jupiter based tests, the `@Tag` annotation (see +<>) should be used. For JUnit 4 based tests, the +Vintage engine maps `@Category` annotations to tags (see +<>). Other testing frameworks may define their +own annotation or other means for users to specify tags. + +[[running-tests-tag-syntax-rules]] +==== Syntax Rules for Tags + +Regardless how a tag is specified, the JUnit Platform enforces the following rules: + +* A tag must not be `null` or _blank_. +* A _stripped_ tag must not contain whitespace. +* A _stripped_ tag must not contain ISO control characters. +* A _stripped_ tag must not contain any of the following _reserved characters_. +- `,`: _comma_ +- `(`: _left parenthesis_ +- `)`: _right parenthesis_ +- `&`: _ampersand_ +- `|`: _vertical bar_ +- `!`: _exclamation point_ + +NOTE: In the above context, "stripped" means that leading and trailing whitespace +characters have been removed using `java.lang.String.strip()`. + +[[running-tests-tag-expressions]] +==== Tag Expressions + +Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, +`(` and `)` can be used to adjust for operator precedence. + +Two special expressions are supported, `any()` and `none()`, which select all tests _with_ +any tags at all, and all tests _without_ any tags, respectively. +These special expressions may be combined with other expressions just like normal tags. + +.Operators (in descending order of precedence) +|=== +| Operator | Meaning | Associativity + +| `!` | not | right +| `&` | and | left +| `\|` | or | left +|=== + +If you are tagging your tests across multiple dimensions, tag expressions help you to +select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, +_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag +expressions can be useful. + +[%header,cols="40,60"] +|=== +| Tag Expression +| Selection + +| `+++product+++` +| all tests for *product* + +| `+++catalog \| shipping+++` +| all tests for *catalog* plus all tests for *shipping* + +| `+++catalog & shipping+++` +| all tests for the intersection between *catalog* and *shipping* + +| `+++product & !end-to-end+++` +| all tests for *product*, but not the _end-to-end_ tests + +| `+++(micro \| integration) & (product \| shipping)+++` +| all _micro_ or _integration_ tests for *product* or *shipping* +|=== + +[[running-tests-capturing-output]] +=== Capturing Standard Output/Error + +The JUnit Platform provides opt-in support for capturing output printed to `System.out` +and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or +`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. + +If enabled, the JUnit Platform captures the corresponding output and publishes it as a +report entry using the `stdout` or `stderr` keys to all registered +`{TestExecutionListener}` instances immediately before reporting the test or container as +finished. + +Please note that the captured output will only contain output emitted by the thread that +was used to execute a container or test. Any output by other threads will be omitted +because particularly when +<> it would be impossible +to attribute it to a specific test or container. + +[[running-tests-listeners]] +=== Using Listeners and Interceptors + +The JUnit Platform provides the following listener APIs that allow JUnit, third parties, +and custom user code to react to events fired at various points during the discovery and +execution of a `TestPlan`. + +* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and + closed. +* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a + `LauncherSession`. +* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. +* `{TestExecutionListener}`: receives events that occur during test execution. + +The `LauncherSessionListener` API is typically implemented by build tools or IDEs and +registered automatically for you in order to support some feature of the build tool or IDE. + +The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in +order to produce some form of report or to display a graphical representation of the test +plan in an IDE. Such listeners may be implemented and automatically registered by a build +tool or IDE, or they may be included in a third-party library – potentially registered +for you automatically. You can also implement and register your own listeners. + +For details on registering and configuring listeners, see the following sections of this +guide. + +* <> +* <> +* <> +* <> +* <> +* <> + +The JUnit Platform provides the following listeners which you may wish to use with your +test suite. + +<> :: + `{LegacyXmlReportGeneratingListener}` can be used via the + <> or registered manually to generate XML reports + compatible with the de facto standard for JUnit 4 based test reports. ++ +`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format +specified by {OpenTestReporting}. It is auto-registered and can be enabled and +configured via <>. ++ +See <> for details. + +<> :: + `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate + Java Flight Recorder events during test discovery and execution. + +`{LoggingListener}` :: + `TestExecutionListener` for logging informational messages for all events via a + `BiConsumer` that consumes `Throwable` and `Supplier`. + +`{SummaryGeneratingListener}` :: + `TestExecutionListener` that generates a summary of the test execution which can be + printed via a `PrintWriter`. + +`{UniqueIdTrackingListener}` :: + `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped + or executed during the execution of the `TestPlan` and generates a file containing the + unique IDs once execution of the `TestPlan` has finished. + +[[running-tests-listeners-flight-recorder]] +==== Flight Recorder Support + +The JUnit Platform provides opt-in support for generating Flight Recorder events. +https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as +follows. + +> Flight Recorder records events originating from applications, the JVM, and the OS. +Events are stored in a single file that can be attached to bug reports and examined by +support engineers, allowing after-the-fact analysis of issues in the period leading up +to a problem. + +In order to record Flight Recorder events generated while running tests, you need to +start flight recording when launching a test suite via the following java command line +option. + + -XX:StartFlightRecording:filename=... + +Please consult the manual of your build tool for the appropriate commands. + +To analyze the recorded events, use the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] +command line tool shipped with recent JDKs or open the recording file with +https://jdk.java.net/jmc/[JDK Mission Control]. + +[[stacktrace-pruning]] +=== Stack Trace Pruning + +The JUnit Platform provides built-in support for pruning stack traces produced by failing +tests. This feature is enabled by default but can be disabled by setting the +`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. + +When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` +packages are removed from the stack trace, unless the calls occur after the test itself +or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will +never be excluded. + +In addition, all elements prior to and including the first call from the JUnit Platform +`Launcher` will be removed. + +[[running-tests-discovery-issues]] +=== Discovery Issues + +Test engines may encounter issues during test discovery. For example, the declaration of a +test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit +Platform provides a <> to +report them with different severity levels: + +INFO:: +Indicates that the engine encountered something that could be potentially problematic, but +could also happen due to a valid setup or configuration. + +WARNING:: +Indicates that the engine encountered something that is problematic and might lead to +unexpected behavior or will be removed or changed in a future release. + +ERROR:: +Indicates that the engine encountered something that is definitely problematic and will +lead to unexpected behavior. + +If an engine reports an issue with a severity equal to or higher than a configurable +_critical_ severity, its tests will not be executed. Instead, the engine will be reported +as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. +Non-critical issues will be logged but will not prevent the engine from executing its +tests. The `junit.platform.discovery.issue.severity.critical` +<> can be used to set the critical +severity level. Currently, the default value is `ERROR` but it may be changed in a future +release. + +TIP: To surface all discovery issues in your project, it is recommended to set the +`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. + +In addition, registered `{LauncherDiscoveryListener}` implementations can receive +discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to +report issues to the user in a more user-friendly way. For example, IDEs may choose to +display all issues in a list or table. From ce6b2b844015ce70e11723bfd8d0135ac9ac2f0d Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:11 +0100 Subject: [PATCH 24/57] Migrate running-tests.adoc sections to Antora --- .../pages/running-tests/build-support.adoc | 667 --------- .../capturing-standard-output-error.adoc | 1196 ---------------- .../configuration-parameters.adoc | 1138 ---------------- .../pages/running-tests/console-launcher.adoc | 1033 -------------- .../pages/running-tests/discovery-issues.adoc | 1180 ---------------- .../running-tests/discovery-selectors.adoc | 1184 ---------------- .../ROOT/pages/running-tests/ide-support.adoc | 1113 --------------- .../ROOT/pages/running-tests/intro.adoc | 1213 ----------------- .../pages/running-tests/source-launcher.adoc | 1183 ---------------- .../running-tests/stack-trace-pruning.adoc | 1201 ---------------- .../ROOT/pages/running-tests/tags.adoc | 1141 ---------------- .../using-listeners-and-interceptors.adoc | 1127 --------------- 12 files changed, 13376 deletions(-) diff --git a/documentation/modules/ROOT/pages/running-tests/build-support.adoc b/documentation/modules/ROOT/pages/running-tests/build-support.adoc index 3099a146c2b4..46ab1eebb6d4 100644 --- a/documentation/modules/ROOT/pages/running-tests/build-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/build-support.adoc @@ -1,109 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - [[running-tests-build]] === Build Support @@ -653,564 +547,3 @@ With Maven you can override the JUnit Jupiter version by including the following ---- -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc index 3099a146c2b4..a74e8fec7b6c 100644 --- a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc +++ b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc @@ -1,1059 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - [[running-tests-capturing-output]] === Capturing Standard Output/Error @@ -1074,143 +18,3 @@ because particularly when <> it would be impossible to attribute it to a specific test or container. -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc index 3099a146c2b4..92b99db8a69b 100644 --- a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc +++ b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc @@ -1,906 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - [[running-tests-config-params]] === Configuration Parameters @@ -979,238 +76,3 @@ Examples: - `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc index 3099a146c2b4..a09e1b1a0584 100644 --- a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc +++ b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc @@ -1,658 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - [[running-tests-console-launcher]] === Console Launcher @@ -836,381 +181,3 @@ DYNAMIC = 35 REPORTED = 37 ---- -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc index 3099a146c2b4..32005494d602 100644 --- a/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc +++ b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc @@ -1,1183 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - [[running-tests-discovery-issues]] === Discovery Issues diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc index 3099a146c2b4..3e912914dd0d 100644 --- a/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc +++ b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc @@ -1,874 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - [[running-tests-discovery-selectors]] === Discovery Selectors @@ -901,316 +30,3 @@ The following discovery selectors are provided out of the box: |=== -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc index 3099a146c2b4..b05f7483572a 100644 --- a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc @@ -1,6 +1,3 @@ -[[running-tests]] -== Running Tests - [[running-tests-ide]] === IDE Support @@ -104,1113 +101,3 @@ If you are using an editor or IDE other than one of those listed in the previous and it doesn't support running tests on the JUnit Platform, you can use the <> to run them from the command line. -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/intro.adoc b/documentation/modules/ROOT/pages/running-tests/intro.adoc index 3099a146c2b4..fa0b0d985b0f 100644 --- a/documentation/modules/ROOT/pages/running-tests/intro.adoc +++ b/documentation/modules/ROOT/pages/running-tests/intro.adoc @@ -1,1216 +1,3 @@ [[running-tests]] == Running Tests -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc index 3099a146c2b4..6de303753743 100644 --- a/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc +++ b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc @@ -1,841 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - [[running-tests-source-launcher]] === Source Launcher @@ -869,348 +31,3 @@ java --module-path lib --add-modules org.junit.start HelloTests.java Find JUnit's class API documentation here: {JUnit} -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc index 3099a146c2b4..afacfdaf0b04 100644 --- a/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc +++ b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc @@ -1,1168 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - [[stacktrace-pruning]] === Stack Trace Pruning @@ -1178,39 +13,3 @@ never be excluded. In addition, all elements prior to and including the first call from the JUnit Platform `Launcher` will be removed. -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/tags.adoc b/documentation/modules/ROOT/pages/running-tests/tags.adoc index 3099a146c2b4..fc83be081ff6 100644 --- a/documentation/modules/ROOT/pages/running-tests/tags.adoc +++ b/documentation/modules/ROOT/pages/running-tests/tags.adoc @@ -1,984 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - [[running-tests-tags]] === Tags @@ -1054,163 +73,3 @@ expressions can be useful. | all _micro_ or _integration_ tests for *product* or *shipping* |=== -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - -[[running-tests-listeners]] -=== Using Listeners and Interceptors - -The JUnit Platform provides the following listener APIs that allow JUnit, third parties, -and custom user code to react to events fired at various points during the discovery and -execution of a `TestPlan`. - -* `{LauncherSessionListener}`: receives events when a `{LauncherSession}` is opened and - closed. -* `{LauncherInterceptor}`: intercepts test discovery and execution in the context of a - `LauncherSession`. -* `{LauncherDiscoveryListener}`: receives events that occur during test discovery. -* `{TestExecutionListener}`: receives events that occur during test execution. - -The `LauncherSessionListener` API is typically implemented by build tools or IDEs and -registered automatically for you in order to support some feature of the build tool or IDE. - -The `LauncherDiscoveryListener` and `TestExecutionListener` APIs are often implemented in -order to produce some form of report or to display a graphical representation of the test -plan in an IDE. Such listeners may be implemented and automatically registered by a build -tool or IDE, or they may be included in a third-party library – potentially registered -for you automatically. You can also implement and register your own listeners. - -For details on registering and configuring listeners, see the following sections of this -guide. - -* <> -* <> -* <> -* <> -* <> -* <> - -The JUnit Platform provides the following listeners which you may wish to use with your -test suite. - -<> :: - `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports - compatible with the de facto standard for JUnit 4 based test reports. -+ -`{OpenTestReportGeneratingListener}` generates an XML report in the event-based format -specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. -+ -See <> for details. - -<> :: - `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate - Java Flight Recorder events during test discovery and execution. - -`{LoggingListener}` :: - `TestExecutionListener` for logging informational messages for all events via a - `BiConsumer` that consumes `Throwable` and `Supplier`. - -`{SummaryGeneratingListener}` :: - `TestExecutionListener` that generates a summary of the test execution which can be - printed via a `PrintWriter`. - -`{UniqueIdTrackingListener}` :: - `TestExecutionListener` that that tracks the unique IDs of all tests that were skipped - or executed during the execution of the `TestPlan` and generates a file containing the - unique IDs once execution of the `TestPlan` has finished. - -[[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support - -The JUnit Platform provides opt-in support for generating Flight Recorder events. -https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as -follows. - -> Flight Recorder records events originating from applications, the JVM, and the OS. -Events are stored in a single file that can be attached to bug reports and examined by -support engineers, allowing after-the-fact analysis of issues in the period leading up -to a problem. - -In order to record Flight Recorder events generated while running tests, you need to -start flight recording when launching a test suite via the following java command line -option. - - -XX:StartFlightRecording:filename=... - -Please consult the manual of your build tool for the appropriate commands. - -To analyze the recorded events, use the -https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] -command line tool shipped with recent JDKs or open the recording file with -https://jdk.java.net/jmc/[JDK Mission Control]. - -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. diff --git a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc index 3099a146c2b4..6b9c40f36be0 100644 --- a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc +++ b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc @@ -1,1079 +1,3 @@ -[[running-tests]] -== Running Tests - -[[running-tests-ide]] -=== IDE Support - -[[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA - -IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more -information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, -however, that it is recommended to use IDEA 2017.3 or newer since more recent versions of -IDEA download the following JARs automatically based on the API version used in the -project: `junit-platform-launcher`, `junit-jupiter-engine`, and `junit-vintage-engine`. - -In order to use a different JUnit version (e.g., {version}), you may need to -include the corresponding versions of the `junit-platform-launcher`, -`junit-jupiter-engine`, and `junit-vintage-engine` JARs in the classpath. - -.Additional Gradle Dependencies -[source,groovy] -[subs=attributes+] ----- -testImplementation(platform("org.junit:junit-bom:{version}")) -testRuntimeOnly("org.junit.platform:junit-platform-launcher") -testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ----- - -.Additional Maven Dependencies -[source,xml] -[subs=attributes+] ----- - - - - org.junit.platform - junit-platform-launcher - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.vintage - junit-vintage-engine - test - - - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -[[running-tests-ide-eclipse]] -==== Eclipse - -Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) -release. - -For more information on using JUnit Platform in Eclipse consult the official _Eclipse -support for JUnit 5_ section of the -https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a -(4.7.1a) - New and Noteworthy] documentation. - -[[running-tests-ide-netbeans]] -==== NetBeans - -NetBeans offers support for JUnit Jupiter and the JUnit Platform since the -https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. - -For more information consult the JUnit 5 section of the -https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 -release notes]. - -[[running-tests-ide-vscode]] -==== Visual Studio Code - -https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit -Platform via the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test[Java Test -Runner] extension which is installed by default as part of the -https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack[Java -Extension Pack]. - -For more information consult the _Testing_ section of the -https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] -documentation. - -[[running-tests-ide-other]] -==== Other IDEs - -If you are using an editor or IDE other than one of those listed in the previous sections, -and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. - -[[running-tests-build]] -=== Build Support - -[[running-tests-build-gradle]] -==== Gradle - -Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides -https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] -for executing tests on the JUnit Platform. To enable it, you need to specify -`useJUnitPlatform()` within a `test` task declaration in `build.gradle`: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform() -} ----- - -Filtering by <>, -<>, or engines is also supported: - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - useJUnitPlatform { - includeTags("fast", "smoke & feature-a") - // excludeTags("slow", "ci") - includeEngines("junit-jupiter") - // excludeEngines("junit-vintage") - } -} ----- - -Please refer to the -https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] -for a comprehensive list of options. - -[[running-tests-build-gradle-bom]] -===== Aligning dependency versions - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Explicit platform dependency on the BOM ----- -dependencies { - testImplementation(platform("org.junit:junit-bom:{version}")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -Since all JUnit artifacts declare a -https://docs.gradle.org/current/userguide/platforms.html[platform] dependency on the BOM, -you usually don't need to declare an explicit dependency on it yourself. Instead, it's -sufficient to declare _one_ regular dependency that includes a version number. Gradle will -then pull in the BOM automatically so you can omit the version for all other JUnit -artifacts. - -[source,groovy,indent=0] -[subs=attributes+] -.Implicit platform dependency on the BOM ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") // <1> - testRuntimeOnly("org.junit.platform:junit-platform-launcher") // <2> -} ----- -<1> Dependency declaration with explicit version. Pulls in the `junit-bom` automatically. -<2> Dependency declaration without version. The version is supplied by the `junit-bom`. - -[WARNING] -.Declaring a dependency on junit-platform-launcher -==== -Even though pre-8.0 versions of Gradle don't require declaring an explicit -dependency on `junit-platform-launcher`, it is recommended to do so to ensure the versions -of JUnit artifacts on the test runtime classpath are aligned. - -Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. -==== - -[[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines - -In order to run any tests at all, a `TestEngine` implementation must be on the classpath. - -To configure support for JUnit Jupiter based tests, configure a `testImplementation` dependency -on the dependency-aggregating JUnit Jupiter artifact similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -Alternatively, you can use Gradle's -https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html[JVM Test Suite] -support. - -[source,kotlin,indent=0] -[subs=attributes+] -.Kotlin DSL ----- -testing { - suites { - named("test") { - useJUnitJupiter("{version}") - } - } -} ----- - -[source,groovy,indent=0] -[subs=attributes+] -.Groovy DSL ----- -testing { - suites { - test { - useJUnitJupiter("{version}") - } - } -} ----- - -The JUnit Platform can run JUnit 4 based tests as long as you configure a `testImplementation` -dependency on JUnit 4 and a `testRuntimeOnly` dependency on the JUnit Vintage `TestEngine` -implementation similar to the following. - -[source,groovy,indent=0] -[subs=attributes+] ----- -dependencies { - testImplementation("junit:junit:{junit4-version}") - testRuntimeOnly("org.junit.vintage:junit-vintage-engine:{version}") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} ----- - -[[running-tests-build-gradle-config-params]] -===== Configuration Parameters - -The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test -discovery and execution. However, you can provide configuration parameters within the -build script via system properties (as shown below) or via the -`junit-platform.properties` file. - -[source,groovy,indent=0] ----- -test { - // ... - systemProperty("junit.jupiter.conditions.deactivate", "*") - systemProperty("junit.jupiter.extensions.autodetection.enabled", true) - systemProperty("junit.jupiter.testinstance.lifecycle.default", "per_class") - // ... -} ----- - -[[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) - -JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to -emit warnings and debug information. Please refer to the official documentation of -`{LogManager}` for configuration options. - -Alternatively, it's possible to redirect log messages to other logging frameworks such as -{Log4j} or {Logback}. To use a logging framework that provides a custom implementation of -`{LogManager}`, set the `java.util.logging.manager` system property to the _fully -qualified class name_ of the `{LogManager}` implementation to use. The example below -demonstrates how to configure Log4j{nbsp}2.x (see {Log4j_JDK_Logging_Adapter} for -details). - -[source,groovy,indent=0] -[subs=attributes+] ----- -test { - systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") - // Avoid overhead (see https://logging.apache.org/log4j/2.x/manual/jmx.html#enabling-jmx) - systemProperty("log4j2.disableJmx", "true") -} ----- - -Other logging frameworks provide different means to redirect messages logged using -`java.util.logging`. For example, for {Logback} you can use the -https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a -dependency to the test runtime classpath. - -[[running-tests-build-maven]] -==== Maven - -Maven Surefire and Maven Failsafe provide -https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] -for executing tests on the JUnit Platform. The `pom.xml` file in the -`{junit-jupiter-starter-maven}` project demonstrates how to use the Maven Surefire plugin -and can serve as a starting point for configuring your Maven build. - -[WARNING] -.Minimum required version of Maven Surefire/Failsafe -==== -As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. -==== - -[[running-tests-build-maven-bom]] -===== Aligning dependency versions - -Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the -versions of all JUnit artifacts. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - org.junit - junit-bom - {version} - pom - import - - - ----- - -Using the BOM allows you to omit the version when declaring dependencies on all artifacts -with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. - -TIP: See <> for details on how to override the version -of JUnit used in your Spring Boot application. - -[[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines - -In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one -`TestEngine` implementation must be added to the test classpath. - -To configure support for JUnit Jupiter based tests, configure `test` scoped dependencies -on the JUnit Jupiter API and the JUnit Jupiter `TestEngine` implementation similar to the -following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - org.junit.jupiter - junit-jupiter - {version} - test - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -Maven Surefire and Maven Failsafe can run JUnit 4 based tests alongside Jupiter tests as -long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintage -`TestEngine` implementation similar to the following. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - junit - junit - {junit4-version} - test - - - org.junit.vintage - junit-vintage-engine - {version} - test - - - - - - - - maven-surefire-plugin - {surefire-version} - - - maven-failsafe-plugin - {surefire-version} - - - - ----- - -[[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names - -The Maven Surefire Plugin will scan for test classes whose fully qualified names match -the following patterns. - -- `+++**/Test*.java+++` -- `+++**/*Test.java+++` -- `+++**/*Tests.java+++` -- `+++**/*TestCase.java+++` - -Moreover, it will exclude all nested classes (including static member classes) by default. - -Note, however, that you can override this default behavior by configuring explicit -`include` and `exclude` rules in your `pom.xml` file. For example, to keep Maven Surefire -from excluding static member classes, you can override its exclude rules as follows. - -[source,xml,indent=0] -[subs=attributes+] -.Overriding exclude rules of Maven Surefire ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - - - - - - ----- - -Please see the -https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] -documentation for Maven Surefire for details. - -[[running-tests-build-maven-filter-tags]] -===== Filtering by Tags - -You can filter tests by <> or -<> using the following configuration -properties. - -- to include _tags_ or _tag expressions_, use `groups`. -- to exclude _tags_ or _tag expressions_, use `excludedGroups`. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - acceptance | !feature-a - integration, regression - - - - - ----- - -[[running-tests-build-maven-config-params]] -===== Configuration Parameters - -You can set JUnit Platform <> to -influence test discovery and execution by declaring the `configurationParameters` -property and providing key-value pairs using the Java `Properties` file syntax (as shown -below) or via the `junit-platform.properties` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - - - - maven-surefire-plugin - {surefire-version} - - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - - - - - - - ----- - -[[running-tests-build-ant]] -==== Ant - -Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that -provides native support for launching tests on the JUnit Platform. The `junitlauncher` -task is solely responsible for launching the JUnit Platform and passing it the selected -collection of tests. The JUnit Platform then delegates to registered test engines to -discover and execute the tests. - -The `junitlauncher` task attempts to align as closely as possible with native Ant -constructs such as -link:https://ant.apache.org/manual/Types/resources.html#collection[resource collections] -for allowing users to select the tests that they want executed by test engines. This gives -the task a consistent and natural feel when compared to many other core Ant tasks. - -Starting with version `1.10.6` of Ant, the `junitlauncher` task supports -link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tests in a separate JVM]. - -The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use -the task and can serve as a starting point. - -===== Basic Usage - -The following example demonstrates how to configure the `junitlauncher` task to select a -single test class (i.e., `com.example.project.CalculatorTests`). - -[source,xml,indent=0] ----- - - - - - - - - - - - ----- - -The `test` element allows you to specify a single test class that you want to be selected -and executed. The `classpath` element allows you to specify the classpath to be used to -launch the JUnit Platform. This classpath will also be used to locate test classes that -are part of the execution. - -The following example demonstrates how to configure the `junitlauncher` task to select -test classes from multiple locations. - -[source,xml,indent=0] ----- - - - - - - - - - - - - - - - - ----- - -In the above example, the `testclasses` element allows you to select multiple test -classes that reside in different locations. - -For further details on usage and configuration options please refer to the official Ant -documentation for the -link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. - -[[running-tests-build-spring-boot]] -==== Spring Boot - -link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for -managing the version of JUnit used in your project. In addition, the -`spring-boot-starter-test` artifact automatically includes testing libraries such as JUnit -Jupiter, AssertJ, Mockito, etc. - -If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would -result in duplicate (and potentially conflicting) management of JUnit dependencies. - -If you need to override the version of a dependency used in your Spring Boot application, -you have to override the exact name of the -link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#appendix.dependency-versions.properties[version property] -defined in the BOM used by the Spring Boot plugin. For example, the name of the JUnit -Jupiter version property in Spring Boot is `junit-jupiter.version`. The mechanism for -changing a dependency version is documented for both -link:https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#managing-dependencies.dependency-management-plugin.customizing[Gradle] -and -link:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#using.parent-pom[Maven]. - -With Gradle you can override the JUnit Jupiter version by including the following in your -`build.gradle` file. - -[source,groovy,indent=0] -[subs=attributes+] ----- - ext['junit-jupiter.version'] = '{version}' ----- - -With Maven you can override the JUnit Jupiter version by including the following in your -`pom.xml` file. - -[source,xml,indent=0] -[subs=attributes+] ----- - - {version} - ----- - -[[running-tests-console-launcher]] -=== Console Launcher - -The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit -Platform from the console. For example, it can be used to run JUnit Vintage and JUnit -Jupiter tests and print test execution results to the console. - -An executable _Fat JAR_ (`junit-platform-console-standalone-{version}.jar`) that -contains the contents of all of its dependencies is published in the {Maven_Central} -repository under the -https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] -directory. It contains the contents of the following artifacts: - -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] - -[NOTE] -==== -Since the `junit-platform-console-standalone` JAR contains the contents of all of its -dependencies, its Maven POM does not declare any dependencies. - -Furthermore, it is not very likely that you would need to include a dependency on the -`junit-platform-console-standalone` artifact in your project's Maven POM or Gradle build -script. On the contrary, the executable `junit-platform-console-standalone` JAR is -typically invoked directly from the command line or a shell script without a build script. - -If you need to declare dependencies in your build script on some of the artifacts -contained in the `junit-platform-console-standalone` artifact, you should declare -dependencies only on the JUnit artifacts that are used in your project. To simplify -dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for -details. -==== - -You can https://docs.oracle.com/javase/tutorial/deployment/jar/run.html[run] the -standalone `ConsoleLauncher` as shown below. - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar execute - -├─ JUnit Vintage -│ └─ example.JUnit4Tests -│ └─ standardJUnit4Test ✔ -└─ JUnit Jupiter - ├─ StandardTests - │ ├─ succeedingTest() ✔ - │ └─ skippedTest() ↷ for demonstration purposes - └─ A special test case - ├─ Custom test name containing spaces ✔ - ├─ ╯°□°)╯ ✔ - └─ 😱 ✔ - -Test run finished after 64 ms -[ 5 containers found ] -[ 0 containers skipped ] -[ 5 containers started ] -[ 0 containers aborted ] -[ 5 containers successful ] -[ 0 containers failed ] -[ 6 tests found ] -[ 1 tests skipped ] -[ 5 tests started ] -[ 0 tests aborted ] -[ 5 tests successful ] -[ 0 tests failed ] ----- - -You can also run the standalone `ConsoleLauncher` as shown below (for example, to include -all jars in a directory): - -[source,console,subs=attributes+] ----- -$ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ----- - -[[running-tests-console-launcher-options]] -==== Subcommands and Options - -The `{ConsoleLauncher}` provides the following subcommands: - ----- -include::{consoleLauncherOptionsFile}[] ----- - -[[running-tests-console-launcher-options-discovering-tests]] -===== Discovering tests - ----- -include::{consoleLauncherDiscoverOptionsFile}[] ----- - -[[running-tests-console-launcher-options-executing-tests]] -===== Executing tests - -.Exit Code -NOTE: On successful runs, the `{ConsoleLauncher}` exits with a status code of `0`. -All non-zero codes indicate an error of some sort. For example, status code `1` -is returned if any containers or tests failed. If no tests are discovered and the -`--fail-if-no-tests` command-line option is supplied, the `ConsoleLauncher` exits -with a status code of `2`. Unexpected or invalid user input yields a status code -of `3`. An exit code of `-1` indicates an unspecified error condition. - ----- -include::{consoleLauncherExecuteOptionsFile}[] ----- - -[[running-tests-console-launcher-options-listing-test-engines]] -===== Listing test engines - ----- -include::{consoleLauncherEnginesOptionsFile}[] ----- - -[[running-tests-console-launcher-argument-files]] -==== Argument Files (@-files) - -On some platforms you may run into system limitations on the length of a command line when -creating a command line with lots of options or with long arguments. - -The `ConsoleLauncher` supports _argument files_, also known as _@-files_. Argument files -are files that themselves contain arguments to be passed to the command. When the -underlying https://github.com/remkop/picocli[picocli] command line parser encounters an -argument beginning with the character `@`, it expands the contents of that file into the -argument list. - -The arguments within a file can be separated by spaces or newlines. If an argument -contains embedded whitespace, the whole argument should be wrapped in double or single -quotes -- for example, `"-f=My Files/Stuff.java"`. - -If the argument file does not exist or cannot be read, the argument will be treated -literally and will not be removed. This will likely result in an "unmatched argument" -error message. You can troubleshoot such errors by executing the command with the -`picocli.trace` system property set to `DEBUG`. - -Multiple _@-files_ may be specified on the command line. The specified path may be -relative to the current directory or absolute. - -You can pass a real parameter with an initial `@` character by escaping it with an -additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be -subject to expansion. - -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] -==== Redirecting Standard Output/Error to Files - -You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to -files using the `--redirect-stdout` and `--redirect-stderr` options: - -[source,console,subs=attributes+] ----- -$ java -jar junit-platform-console-standalone-{version}.jar \ - --redirect-stdout=stdout.txt \ - --redirect-stderr=stderr.txt ----- - -[NOTE] -==== -If the `--redirect-stdout` and `--redirect-stderr` arguments point to the same file, both -output streams will be redirected to that file. - -The default charset is used for writing to the files. -==== - -[[running-tests-console-launcher-color-customization]] -==== Color Customization - -The colors used in the output of the `{ConsoleLauncher}` can be customized. -The option `--single-color` will apply a built-in monochrome style, while -`--color-palette` will accept a properties file to override the -https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[ANSI SGR] color styling. -The properties file below demonstrates the default style: - -[source,properties,indent=0] ----- -SUCCESSFUL = 32 -ABORTED = 33 -FAILED = 31 -SKIPPED = 35 -CONTAINER = 35 -TEST = 34 -DYNAMIC = 35 -REPORTED = 37 ----- - -[[running-tests-source-launcher]] -=== Source Launcher - -Starting with Java 25 it is possible to write minimal source code test programs -using the `org.junit.start` module. For example, like in a `HelloTests.java` -file reading: - -```java -import module org.junit.start; - -void main() { - JUnit.run(); -} - -@Test -void stringLength() { - Assertions.assertEquals(11, "Hello JUnit".length()); -} -``` -With all required modular JAR files available in a local `lib/` directory, the -following Java 25+ command will discover and execute tests using the JUnit Platform. -It will also print the result tree to the console. - -```shell -java --module-path lib --add-modules org.junit.start HelloTests.java -╷ -└─ JUnit Jupiter ✔ - └─ HelloTests ✔ - └─ stringLength() ✔ -``` - -Find JUnit's class API documentation here: {JUnit} - -[[running-tests-discovery-selectors]] -=== Discovery Selectors - -The JUnit Platform provides a rich set of discovery selectors that can be used to specify -which tests should be discovered or executed. - -Discovery selectors can be created programmatically using the factory methods in the -`{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or -generically as strings via their identifiers. - -The following discovery selectors are provided out of the box: - -|=== -| Java Type | API | Annotation | Console Launcher | Identifier - -| `{ClasspathResourceSelector}` | `{DiscoverySelectors_selectClasspathResource}` | `{SelectClasspathResource}` | `--select-resource /foo.csv` | `resource:/foo.csv` -| `{ClasspathRootSelector}` | `{DiscoverySelectors_selectClasspathRoots}` | -- | `--scan-classpath bin` | `classpath-root:bin` -| `{ClassSelector}` | `{DiscoverySelectors_selectClass}` | `{SelectClasses}` | `--select-class com.acme.Foo` | `class:com.acme.Foo` -| `{DirectorySelector}` | `{DiscoverySelectors_selectDirectory}` | `{SelectDirectories}` | `--select-directory foo/bar` | `directory:foo/bar` -| `{FileSelector}` | `{DiscoverySelectors_selectFile}` | `{SelectFile}` | `--select-file dir/foo.txt` | `file:dir/foo.txt` -| `{IterationSelector}` | `{DiscoverySelectors_selectIteration}` | `{Select}("")` | `--select-iteration method=com.acme.Foo#m[1..2]` | `iteration:method:com.acme.Foo#m[1..2]` -| `{MethodSelector}` | `{DiscoverySelectors_selectMethod}` | `{SelectMethod}` | `--select-method com.acme.Foo#m` | `method:com.acme.Foo#m` -| `{ModuleSelector}` | `{DiscoverySelectors_selectModule}` | `{SelectModules}` | `--select-module com.acme` | `module:com.acme` -| `{NestedClassSelector}` | `{DiscoverySelectors_selectNestedClass}` | `{Select}("")` | `--select ` | `nested-class:com.acme.Foo/Bar` -| `{NestedMethodSelector}` | `{DiscoverySelectors_selectNestedMethod}` | `{Select}("")` | `--select ` | `nested-method:com.acme.Foo/Bar#m` -| `{PackageSelector}` | `{DiscoverySelectors_selectPackage}` | `{SelectPackages}` | `--select-package com.acme.foo` | `package:com.acme.foo` -| `{UniqueIdSelector}` | `{DiscoverySelectors_selectUniqueId}` | `{Select}("")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` -| `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` -|=== - - -[[running-tests-config-params]] -=== Configuration Parameters - -In addition to instructing the platform which test classes and test engines to include, -which packages to scan, etc., it is sometimes necessary to provide additional custom -configuration parameters that are specific to a particular test engine, listener, or -registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration -parameters_ for the following use cases. - -- <> -- <> -- <> -- <> - -_Configuration Parameters_ are text-based key-value pairs that can be supplied to test -engines running on the JUnit Platform via one of the following mechanisms. - -1. The `configurationParameter()` and `configurationParameters()` methods in - `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. - + - When running tests via one of the tools provided by the JUnit Platform you can specify - configuration parameters as follows: - * <>: use the `--config` command-line - option. - * <>: use the `systemProperty` or - `systemProperties` DSL. - * <>: use the - `configurationParameters` property. -2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. - + - When running tests via the <> you can - specify custom configuration files using the `--config-resource` command-line option. -3. JVM system properties. -4. The JUnit Platform default configuration file: a file named `junit-platform.properties` - in the root of the class path that follows the syntax rules for Java `Properties` - files. - -NOTE: Configuration parameters are looked up in the exact order defined above. -Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via custom configuration files, system properties, and the -default configuration file. Similarly, configuration parameters supplied via system -properties take precedence over those supplied via the default configuration file. - -[[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax - -This section describes the pattern matching syntax that is applied to the _configuration -parameters_ used for the following features. - -- <> -- <> -- <> -- <> - -If the value for the given _configuration parameter_ consists solely of an asterisk -(`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value -will be treated as a comma-separated list of patterns where each pattern will be matched -against the fully qualified class name (_FQCN_) of each candidate class. Any dot (`.`) in -a pattern will match against a dot (`.`) or a dollar sign (`$`) in a FQCN. Any asterisk -(`+++*+++`) will match against one or more characters in a FQCN. All other characters in a -pattern will be matched one-to-one against a FQCN. - -Examples: - -- `+++*+++`: matches all candidate classes. -- `+++org.junit.*+++`: matches all candidate classes under the `org.junit` base package and - any of its subpackages. -- `+++*.MyCustomImpl+++`: matches every candidate class whose simple class name is exactly - `MyCustomImpl`. -- `+++*System*+++`: matches every candidate class whose FQCN contains `System`. -- `+++*System*+++, +++*Unit*+++`: matches every candidate class whose FQCN contains - `System` or `Unit`. -- `org.example.MyCustomImpl`: matches the candidate class whose FQCN is exactly - `org.example.MyCustomImpl`. -- `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose - FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - -[[running-tests-tags]] -=== Tags - -Tags are a JUnit Platform concept for marking and filtering tests. The programming model -for adding tags to containers and tests is defined by the testing framework. For example, -in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the -Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their -own annotation or other means for users to specify tags. - -[[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags - -Regardless how a tag is specified, the JUnit Platform enforces the following rules: - -* A tag must not be `null` or _blank_. -* A _stripped_ tag must not contain whitespace. -* A _stripped_ tag must not contain ISO control characters. -* A _stripped_ tag must not contain any of the following _reserved characters_. -- `,`: _comma_ -- `(`: _left parenthesis_ -- `)`: _right parenthesis_ -- `&`: _ampersand_ -- `|`: _vertical bar_ -- `!`: _exclamation point_ - -NOTE: In the above context, "stripped" means that leading and trailing whitespace -characters have been removed using `java.lang.String.strip()`. - -[[running-tests-tag-expressions]] -==== Tag Expressions - -Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, -`(` and `)` can be used to adjust for operator precedence. - -Two special expressions are supported, `any()` and `none()`, which select all tests _with_ -any tags at all, and all tests _without_ any tags, respectively. -These special expressions may be combined with other expressions just like normal tags. - -.Operators (in descending order of precedence) -|=== -| Operator | Meaning | Associativity - -| `!` | not | right -| `&` | and | left -| `\|` | or | left -|=== - -If you are tagging your tests across multiple dimensions, tag expressions help you to -select which tests to execute. When tagging by test type (e.g., _micro_, _integration_, -_end-to-end_) and feature (e.g., *product*, *catalog*, *shipping*), the following tag -expressions can be useful. - -[%header,cols="40,60"] -|=== -| Tag Expression -| Selection - -| `+++product+++` -| all tests for *product* - -| `+++catalog \| shipping+++` -| all tests for *catalog* plus all tests for *shipping* - -| `+++catalog & shipping+++` -| all tests for the intersection between *catalog* and *shipping* - -| `+++product & !end-to-end+++` -| all tests for *product*, but not the _end-to-end_ tests - -| `+++(micro \| integration) & (product \| shipping)+++` -| all _micro_ or _integration_ tests for *product* or *shipping* -|=== - -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error - -The JUnit Platform provides opt-in support for capturing output printed to `System.out` -and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes -to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. - -If enabled, the JUnit Platform captures the corresponding output and publishes it as a -report entry using the `stdout` or `stderr` keys to all registered -`{TestExecutionListener}` instances immediately before reporting the test or container as -finished. - -Please note that the captured output will only contain output emitted by the thread that -was used to execute a container or test. Any output by other threads will be omitted -because particularly when -<> it would be impossible -to attribute it to a specific test or container. - [[running-tests-listeners]] === Using Listeners and Interceptors @@ -1163,54 +87,3 @@ https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] command line tool shipped with recent JDKs or open the recording file with https://jdk.java.net/jmc/[JDK Mission Control]. -[[stacktrace-pruning]] -=== Stack Trace Pruning - -The JUnit Platform provides built-in support for pruning stack traces produced by failing -tests. This feature is enabled by default but can be disabled by setting the -`junit.platform.stacktrace.pruning.enabled` _configuration parameter_ to `false`. - -When enabled, all calls from the `org.junit`, `jdk.internal.reflect`, and `sun.reflect` -packages are removed from the stack trace, unless the calls occur after the test itself -or any of its ancestors. For that reason, calls to `{Assertions}` or `{Assumptions}` will -never be excluded. - -In addition, all elements prior to and including the first call from the JUnit Platform -`Launcher` will be removed. - -[[running-tests-discovery-issues]] -=== Discovery Issues - -Test engines may encounter issues during test discovery. For example, the declaration of a -test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to -report them with different severity levels: - -INFO:: -Indicates that the engine encountered something that could be potentially problematic, but -could also happen due to a valid setup or configuration. - -WARNING:: -Indicates that the engine encountered something that is problematic and might lead to -unexpected behavior or will be removed or changed in a future release. - -ERROR:: -Indicates that the engine encountered something that is definitely problematic and will -lead to unexpected behavior. - -If an engine reports an issue with a severity equal to or higher than a configurable -_critical_ severity, its tests will not be executed. Instead, the engine will be reported -as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. -Non-critical issues will be logged but will not prevent the engine from executing its -tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical -severity level. Currently, the default value is `ERROR` but it may be changed in a future -release. - -TIP: To surface all discovery issues in your project, it is recommended to set the -`junit.platform.discovery.issue.severity.critical` configuration parameter to `INFO`. - -In addition, registered `{LauncherDiscoveryListener}` implementations can receive -discovery issues via the `issueEncountered()` method. This allows IDEs and build tools to -report issues to the user in a more user-friendly way. For example, IDEs may choose to -display all issues in a list or table. From 9a915125a3438d1c989526c1cbb2100595ca0fb3 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:11 +0100 Subject: [PATCH 25/57] Migrate running-tests sections to Antora syntax --- .../pages/running-tests/build-support.adoc | 32 +++++++++---------- .../capturing-standard-output-error.adoc | 4 +-- .../configuration-parameters.adoc | 6 ++-- .../pages/running-tests/console-launcher.adoc | 18 +++++------ .../pages/running-tests/discovery-issues.adoc | 3 +- .../running-tests/discovery-selectors.adoc | 5 +-- .../ROOT/pages/running-tests/ide-support.adoc | 14 ++++---- .../ROOT/pages/running-tests/intro.adoc | 4 +-- .../pages/running-tests/source-launcher.adoc | 4 +-- .../running-tests/stack-trace-pruning.adoc | 4 +-- .../ROOT/pages/running-tests/tags.adoc | 8 ++--- .../using-listeners-and-interceptors.adoc | 6 ++-- 12 files changed, 43 insertions(+), 65 deletions(-) diff --git a/documentation/modules/ROOT/pages/running-tests/build-support.adoc b/documentation/modules/ROOT/pages/running-tests/build-support.adoc index 46ab1eebb6d4..dcb14a1d1ec0 100644 --- a/documentation/modules/ROOT/pages/running-tests/build-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/build-support.adoc @@ -1,8 +1,7 @@ -[[running-tests-build]] -=== Build Support += Build Support [[running-tests-build-gradle]] -==== Gradle +== Gradle Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides https://docs.gradle.org/current/userguide/java_testing.html#using_junit5[native support] @@ -38,7 +37,7 @@ https://docs.gradle.org/current/userguide/java_testing.html[official Gradle docu for a comprehensive list of options. [[running-tests-build-gradle-bom]] -===== Aligning dependency versions +=== Aligning dependency versions TIP: See <> for details on how to override the version of JUnit used in your Spring Boot application. @@ -93,7 +92,7 @@ project into an IDE like <> or ==== [[running-tests-build-gradle-engines-configure]] -===== Configuring Test Engines +=== Configuring Test Engines In order to run any tests at all, a `TestEngine` implementation must be on the classpath. @@ -154,7 +153,7 @@ dependencies { ---- [[running-tests-build-gradle-config-params]] -===== Configuration Parameters +=== Configuration Parameters The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit Platform <> to influence test @@ -174,7 +173,7 @@ test { ---- [[running-tests-build-gradle-logging]] -===== Configuring Logging (optional) +=== Configuring Logging (optional) JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to emit warnings and debug information. Please refer to the official documentation of @@ -203,7 +202,7 @@ https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it dependency to the test runtime classpath. [[running-tests-build-maven]] -==== Maven +== Maven Maven Surefire and Maven Failsafe provide https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html[native support] @@ -218,7 +217,7 @@ As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0. ==== [[running-tests-build-maven-bom]] -===== Aligning dependency versions +=== Aligning dependency versions Unless you're using Spring Boot which defines its own way of managing dependencies, it is recommended to use the JUnit Platform <> to align the @@ -247,7 +246,7 @@ TIP: See <> for details on how to override the of JUnit used in your Spring Boot application. [[running-tests-build-maven-engines-configure]] -===== Configuring Test Engines +=== Configuring Test Engines In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one `TestEngine` implementation must be added to the test classpath. @@ -326,7 +325,7 @@ long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintag ---- [[running-tests-build-maven-filter-test-class-names]] -===== Filtering by Test Class Names +=== Filtering by Test Class Names The Maven Surefire Plugin will scan for test classes whose fully qualified names match the following patterns. @@ -368,7 +367,7 @@ https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclu documentation for Maven Surefire for details. [[running-tests-build-maven-filter-tags]] -===== Filtering by Tags +=== Filtering by Tags You can filter tests by <> or <> using the following configuration @@ -397,7 +396,7 @@ properties. ---- [[running-tests-build-maven-config-params]] -===== Configuration Parameters +=== Configuration Parameters You can set JUnit Platform <> to influence test discovery and execution by declaring the `configurationParameters` @@ -429,7 +428,7 @@ below) or via the `junit-platform.properties` file. ---- [[running-tests-build-ant]] -==== Ant +== Ant Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher`] task that @@ -450,7 +449,7 @@ link:https://ant.apache.org/manual/Tasks/junitlauncher.html#fork[forking the tes The `build.xml` file in the `{junit-jupiter-starter-ant}` project demonstrates how to use the task and can serve as a starting point. -===== Basic Usage +=== Basic Usage The following example demonstrates how to configure the `junitlauncher` task to select a single test class (i.e., `com.example.project.CalculatorTests`). @@ -506,7 +505,7 @@ documentation for the link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. [[running-tests-build-spring-boot]] -==== Spring Boot +== Spring Boot link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for managing the version of JUnit used in your project. In addition, the @@ -546,4 +545,3 @@ With Maven you can override the JUnit Jupiter version by including the following {version} ---- - diff --git a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc index a74e8fec7b6c..a8d6ca7e0509 100644 --- a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc +++ b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc @@ -1,5 +1,4 @@ -[[running-tests-capturing-output]] -=== Capturing Standard Output/Error += Capturing Standard Output/Error The JUnit Platform provides opt-in support for capturing output printed to `System.out` and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or @@ -17,4 +16,3 @@ was used to execute a container or test. Any output by other threads will be omi because particularly when <> it would be impossible to attribute it to a specific test or container. - diff --git a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc index 92b99db8a69b..5e43efa01b84 100644 --- a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc +++ b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc @@ -1,5 +1,4 @@ -[[running-tests-config-params]] -=== Configuration Parameters += Configuration Parameters In addition to instructing the platform which test classes and test engines to include, which packages to scan, etc., it is sometimes necessary to provide additional custom @@ -43,7 +42,7 @@ default configuration file. Similarly, configuration parameters supplied via sys properties take precedence over those supplied via the default configuration file. [[running-tests-config-params-deactivation-pattern]] -==== Pattern Matching Syntax +== Pattern Matching Syntax This section describes the pattern matching syntax that is applied to the _configuration parameters_ used for the following features. @@ -75,4 +74,3 @@ Examples: `org.example.MyCustomImpl`. - `org.example.MyCustomImpl, org.example.TheirCustomImpl`: matches candidate classes whose FQCN is exactly `org.example.MyCustomImpl` or `org.example.TheirCustomImpl`. - diff --git a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc index a09e1b1a0584..75ae13ce2f7f 100644 --- a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc +++ b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc @@ -1,5 +1,4 @@ -[[running-tests-console-launcher]] -=== Console Launcher += Console Launcher The `{ConsoleLauncher}` is a command-line Java application that lets you launch the JUnit Platform from the console. For example, it can be used to run JUnit Vintage and JUnit @@ -74,7 +73,7 @@ $ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ")` | `--select-unique-id ` | `uid:[engine:Foo]/[segment:Bar]` | `{UriSelector}` | `{DiscoverySelectors_selectUri}` | `{SelectUris}` | `--select-uri \file:///foo.txt` | `uri:file:///foo.txt` |=== - - diff --git a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc index b05f7483572a..d3330c3c1038 100644 --- a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc @@ -1,8 +1,7 @@ -[[running-tests-ide]] -=== IDE Support += IDE Support [[running-tests-ide-intellij-idea]] -==== IntelliJ IDEA +== IntelliJ IDEA IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more information, please consult this https://jb.gg/junit-idea/[IntelliJ IDEA resource]. Note, @@ -60,7 +59,7 @@ testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ---- [[running-tests-ide-eclipse]] -==== Eclipse +== Eclipse Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) release. @@ -71,7 +70,7 @@ https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxy (4.7.1a) - New and Noteworthy] documentation. [[running-tests-ide-netbeans]] -==== NetBeans +== NetBeans NetBeans offers support for JUnit Jupiter and the JUnit Platform since the https://netbeans.apache.org/download/nb100/nb100.html[Apache NetBeans 10.0 release]. @@ -81,7 +80,7 @@ https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 1 release notes]. [[running-tests-ide-vscode]] -==== Visual Studio Code +== Visual Studio Code https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit Platform via the @@ -95,9 +94,8 @@ https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio documentation. [[running-tests-ide-other]] -==== Other IDEs +== Other IDEs If you are using an editor or IDE other than one of those listed in the previous sections, and it doesn't support running tests on the JUnit Platform, you can use the <> to run them from the command line. - diff --git a/documentation/modules/ROOT/pages/running-tests/intro.adoc b/documentation/modules/ROOT/pages/running-tests/intro.adoc index fa0b0d985b0f..82162ef9cb47 100644 --- a/documentation/modules/ROOT/pages/running-tests/intro.adoc +++ b/documentation/modules/ROOT/pages/running-tests/intro.adoc @@ -1,3 +1,3 @@ -[[running-tests]] -== Running Tests += Running Tests +This section explains how to run tests from IDEs and build tools. diff --git a/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc index 6de303753743..151cfd54b99f 100644 --- a/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc +++ b/documentation/modules/ROOT/pages/running-tests/source-launcher.adoc @@ -1,5 +1,4 @@ -[[running-tests-source-launcher]] -=== Source Launcher += Source Launcher Starting with Java 25 it is possible to write minimal source code test programs using the `org.junit.start` module. For example, like in a `HelloTests.java` @@ -30,4 +29,3 @@ java --module-path lib --add-modules org.junit.start HelloTests.java ``` Find JUnit's class API documentation here: {JUnit} - diff --git a/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc index afacfdaf0b04..a3161def7e75 100644 --- a/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc +++ b/documentation/modules/ROOT/pages/running-tests/stack-trace-pruning.adoc @@ -1,5 +1,4 @@ -[[stacktrace-pruning]] -=== Stack Trace Pruning += Stack Trace Pruning The JUnit Platform provides built-in support for pruning stack traces produced by failing tests. This feature is enabled by default but can be disabled by setting the @@ -12,4 +11,3 @@ never be excluded. In addition, all elements prior to and including the first call from the JUnit Platform `Launcher` will be removed. - diff --git a/documentation/modules/ROOT/pages/running-tests/tags.adoc b/documentation/modules/ROOT/pages/running-tests/tags.adoc index fc83be081ff6..79c807264375 100644 --- a/documentation/modules/ROOT/pages/running-tests/tags.adoc +++ b/documentation/modules/ROOT/pages/running-tests/tags.adoc @@ -1,5 +1,4 @@ -[[running-tests-tags]] -=== Tags += Tags Tags are a JUnit Platform concept for marking and filtering tests. The programming model for adding tags to containers and tests is defined by the testing framework. For example, @@ -10,7 +9,7 @@ Vintage engine maps `@Category` annotations to tags (see own annotation or other means for users to specify tags. [[running-tests-tag-syntax-rules]] -==== Syntax Rules for Tags +== Syntax Rules for Tags Regardless how a tag is specified, the JUnit Platform enforces the following rules: @@ -29,7 +28,7 @@ NOTE: In the above context, "stripped" means that leading and trailing whitespac characters have been removed using `java.lang.String.strip()`. [[running-tests-tag-expressions]] -==== Tag Expressions +== Tag Expressions Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, `(` and `)` can be used to adjust for operator precedence. @@ -72,4 +71,3 @@ expressions can be useful. | `+++(micro \| integration) & (product \| shipping)+++` | all _micro_ or _integration_ tests for *product* or *shipping* |=== - diff --git a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc index 6b9c40f36be0..8e03a5a22c94 100644 --- a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc +++ b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc @@ -1,5 +1,4 @@ -[[running-tests-listeners]] -=== Using Listeners and Interceptors += Using Listeners and Interceptors The JUnit Platform provides the following listener APIs that allow JUnit, third parties, and custom user code to react to events fired at various points during the discovery and @@ -63,7 +62,7 @@ See <> for details. unique IDs once execution of the `TestPlan` has finished. [[running-tests-listeners-flight-recorder]] -==== Flight Recorder Support +== Flight Recorder Support The JUnit Platform provides opt-in support for generating Flight Recorder events. https://openjdk.java.net/jeps/328[JEP 328] describes the Java Flight Recorder (JFR) as @@ -86,4 +85,3 @@ To analyze the recorded events, use the https://docs.oracle.com/en/java/javase/17/docs/specs/man/jfr.html[jfr] command line tool shipped with recent JDKs or open the recording file with https://jdk.java.net/jmc/[JDK Mission Control]. - From 8f2ab798b4c2ccd35d8a3ede87efea63b823b577 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:12 +0100 Subject: [PATCH 26/57] Add running-tests sections to navigation --- documentation/modules/ROOT/nav.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 96c84890418b..37c8b335fa42 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -24,3 +24,15 @@ ** xref:writing-tests/parallel-execution.adoc[] ** xref:writing-tests/built-in-extensions.adoc[] * xref:migrating-from-junit4.adoc[] +* xref:running-tests/intro.adoc[] +** xref:running-tests/ide-support.adoc[] +** xref:running-tests/build-support.adoc[] +** xref:running-tests/console-launcher.adoc[] +** xref:running-tests/source-launcher.adoc[] +** xref:running-tests/discovery-selectors.adoc[] +** xref:running-tests/configuration-parameters.adoc[] +** xref:running-tests/tags.adoc[] +** xref:running-tests/capturing-standard-output-error.adoc[] +** xref:running-tests/using-listeners-and-interceptors.adoc[] +** xref:running-tests/stack-trace-pruning.adoc[] +** xref:running-tests/discovery-issues.adoc[] From 6ffb4857d69f9a5441a51fcd30994d7095bbf585 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:12 +0100 Subject: [PATCH 27/57] Move extensions.adoc to Antora module --- .../conditional-test-execution.adoc} | 0 .../pages/extensions/exception-handling.adoc | 1257 +++++++++++++++++ .../extensions/intercepting-invocations.adoc | 1257 +++++++++++++++++ .../keeping-state-in-extensions.adoc | 1257 +++++++++++++++++ .../ROOT/pages/extensions/overview.adoc | 1257 +++++++++++++++++ .../extensions/parameter-resolution.adoc | 1257 +++++++++++++++++ .../extensions/pre-interrupt-callback.adoc | 1257 +++++++++++++++++ ...vocation-contexts-for-class-templates.adoc | 1257 +++++++++++++++++ ...nvocation-contexts-for-test-templates.adoc | 1257 +++++++++++++++++ .../extensions/registering-extensions.adoc | 1257 +++++++++++++++++ ...ion-order-of-user-code-and-extensions.adoc | 1257 +++++++++++++++++ .../supported-utilities-in-extensions.adoc | 1257 +++++++++++++++++ .../extensions/test-instance-factories.adoc | 1257 +++++++++++++++++ .../test-instance-post-processing.adoc | 1257 +++++++++++++++++ .../test-instance-pre-construct-callback.adoc | 1257 +++++++++++++++++ .../test-instance-pre-destroy-callback.adoc | 1257 +++++++++++++++++ .../extensions/test-lifecycle-callbacks.adoc | 1257 +++++++++++++++++ .../extensions/test-result-processing.adoc | 1257 +++++++++++++++++ 18 files changed, 21369 insertions(+) rename documentation/{src/docs/asciidoc/user-guide/extensions.adoc => modules/ROOT/pages/extensions/conditional-test-execution.adoc} (100%) create mode 100644 documentation/modules/ROOT/pages/extensions/exception-handling.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/overview.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/registering-extensions.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc create mode 100644 documentation/modules/ROOT/pages/extensions/test-result-processing.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/extensions.adoc b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/extensions.adoc rename to documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc diff --git a/documentation/modules/ROOT/pages/extensions/exception-handling.adoc b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/overview.adoc b/documentation/modules/ROOT/pages/extensions/overview.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/overview.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== diff --git a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc new file mode 100644 index 000000000000..213721b04e2c --- /dev/null +++ b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc @@ -0,0 +1,1257 @@ +:testDir: ../../../../src/test/java +:kotlinTestDir: ../../../../src/test/kotlin + +[[extensions]] +== Extension Model + +[[extensions-overview]] +=== Overview + +In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in +JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the +`Extension` API. Note, however, that `Extension` itself is just a marker interface. + +[[extensions-registration]] +=== Registering Extensions + +Extensions can be registered _declaratively_ via +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. + +[[extensions-registration-declarative]] +==== Declarative Extension Registration + +Developers can register one or more extensions _declaratively_ by annotating a test +interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +register. `@ExtendWith` may also be declared on fields or on parameters in test class +constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and +`@AfterEach` lifecycle methods. + +For example, to register a `WebServerExtension` for a particular test method, you would +annotate the test method as follows. We assume the `WebServerExtension` starts a local web +server and injects the server's URL into parameters annotated with `@WebServerUrl`. + +[source,java,indent=0] +---- +@Test +@ExtendWith(WebServerExtension.class) +void getProductList(@WebServerUrl String serverUrl) { + WebClient webClient = new WebClient(); + // Use WebClient to connect to web server using serverUrl and verify response + assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); +} +---- + +To register the `WebServerExtension` for all tests in a particular class and its +subclasses, you would annotate the test class as follows. + +[source,java,indent=0] +---- +@ExtendWith(WebServerExtension.class) +class MyTests { + // ... +} +---- + +Multiple extensions can be registered together like this: + +[source,java,indent=0] +---- +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +class MyFirstTests { + // ... +} +---- + +As an alternative, multiple extensions can be registered separately like this: + +[source,java,indent=0] +---- +@ExtendWith(DatabaseExtension.class) +@ExtendWith(WebServerExtension.class) +class MySecondTests { + // ... +} +---- + +[TIP] +.Extension Registration Order +==== +Extensions registered declaratively via `@ExtendWith` at the class level, method level, or +parameter level will be executed in the order in which they are declared in the source +code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will +be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. +==== + +If you wish to combine multiple extensions in a reusable way, you can define a custom +_<>_ and use `@ExtendWith` as a +_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` +can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. + +[source,java,indent=0] +---- +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) +public @interface DatabaseAndWebServerExtension { +} +---- + +The above examples demonstrate how `@ExtendWith` can be applied at the class level or at +the method level; however, for certain use cases it makes sense for an extension to be +registered declaratively at the field or parameter level. Consider a +`RandomNumberExtension` which generates random numbers that can be injected into a field or +via a parameter in a constructor, test method, or lifecycle method. If the extension +provides a `@Random` annotation that is meta-annotated with +`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used +transparently as in the following `RandomNumberDemo` example. + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/Random.java[tags=user_guide] +---- + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] +---- + +[[extensions-RandomNumberExtension]] +The following code listing provides an example of how one might choose to implement such a +`RandomNumberExtension`. This implementation works for the use cases in +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is +important to note which extension APIs are implemented and for what reasons. + +Specifically, `RandomNumberExtension` implements the following extension APIs: + +- `BeforeAllCallback`: to support static field injection +- `TestInstancePostProcessor`: to support non-static field injection +- `ParameterResolver`: to support constructor and method injection + +[source,java,indent=0] +---- +include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] +---- + +[TIP] +.Extension Registration Order for `@ExtendWith` on Fields +==== +Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative +to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is +deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be +inherited. + +See <> for details. +==== + +NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on +<> and +<> for +`@RegisterExtension` fields also applies to `@ExtendWith` fields. + +[[extensions-registration-programmatic]] +==== Programmatic Extension Registration + +Developers can register extensions _programmatically_ by annotating fields in test classes +with `{RegisterExtension}`. + +When an extension is registered _declaratively_ via +<>, it can typically only be configured +via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it +can be configured _programmatically_ -- for example, in order to pass arguments to the +extension's constructor, a static factory method, or a builder API. + +[[extensions-registration-programmatic-order]] +[TIP] +.Extension Registration Order +==== +By default, extensions registered programmatically via `@RegisterExtension` or +declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is +deterministic but intentionally nonobvious. This ensures that subsequent runs of a test +suite execute extensions in the same order, thereby allowing for repeatable builds. +However, there are times when extensions need to be registered in an explicit order. To +achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. + +Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be +ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This +allows `@Order` annotated extension fields to be explicitly ordered before or after +non-annotated extension fields. Extensions with an explicit order value less than the +default order value will be registered before non-annotated extensions. Similarly, +extensions with an explicit order value greater than the default order value will be +registered after non-annotated extensions. For example, assigning an extension an explicit +order value that is greater than the default order value allows _before_ callback +extensions to be registered last and _after_ callback extensions to be registered first, +relative to other programmatically registered extensions. +==== + +[TIP] +.Extension Inheritance +==== +Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses +will be inherited. + +See <> for details. +==== + +NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be +either `static` or non-static. + +[[extensions-registration-programmatic-static-fields]] +===== Static Fields + +If a `@RegisterExtension` field is `static`, the extension will be registered after +extensions that are registered at the class level via `@ExtendWith`. Such _static +extensions_ are not limited in which extension APIs they can implement. Extensions +registered via static fields may therefore implement class-level and instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, +`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level +extension APIs such as `BeforeEachCallback`, etc. + +In the following example, the `server` field in the test class is initialized +programmatically by using a builder pattern supported by the `WebServerExtension`. The +configured `WebServerExtension` will be automatically registered as an extension at the +class level -- for example, in order to start the server before all tests in the class +and then stop the server after all tests in the class have completed. In addition, static +lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, +`@AfterEach`, and `@Test` methods can access the instance of the extension via the +`server` field if necessary. + +[source,java,indent=0] +.Registering an extension via a static field in Java +---- +include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] +---- + +[[extensions-registration-programmatic-static-fields-kotlin]] +====== Static Fields in Kotlin + +The Kotlin programming language does not have the concept of a `static` field. However, +the compiler can be instructed to generate a `private static` field using the `@JvmStatic` +annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, +you can use the `@JvmField` annotation instead. + +The following example is a version of the `WebServerDemo` from the previous section that +has been ported to Kotlin. + +[source,kotlin,indent=0] +.Registering an extension via a static field in Kotlin +---- +include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] +---- + +[[extensions-registration-programmatic-instance-fields]] +===== Instance Fields + +If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension +will be registered after the test class has been instantiated and after each registered +`TestInstancePostProcessor` has been given a chance to post-process the test instance +(potentially injecting the instance of the extension to be used into the annotated +field). Thus, if such an _instance extension_ implements class-level or instance-level +extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or +`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be +registered _before_ extensions that are registered at the method level via `@ExtendWith`. + +In the following example, the `docs` field in the test class is initialized +programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result +to the static `forPath()` factory method in the `DocumentationExtension`. The configured +`DocumentationExtension` will be automatically registered as an extension at the method +level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the +instance of the extension via the `docs` field if necessary. + +[source,java,indent=0] +.An extension registered via an instance field +---- +include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] +---- + +[[extensions-registration-automatic]] +==== Automatic Extension Registration + +In addition to <> +and <> support +using annotations, JUnit Jupiter also supports _global extension registration_ via Java's +`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and +automatically registered based on what is available in the classpath. + +Specifically, a custom extension can be registered by supplying its fully qualified class +name in a file named `org.junit.jupiter.api.extension.Extension` within the +`/META-INF/services` folder in its enclosing JAR file. + +[[extensions-registration-automatic-enabling]] +===== Enabling Automatic Extension Detection + +Auto-detection is an advanced feature and is therefore not enabled by default. To enable +it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to +`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in +the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to enable auto-detection of extensions, you can start your JVM with the +following system property. + +`-Djunit.jupiter.extensions.autodetection.enabled=true` + +When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism +will be added to the extension registry after JUnit Jupiter's global extensions (e.g., +support for `TestInfo`, `TestReporter`, etc.). + +[[extensions-registration-automatic-filtering]] +===== Filtering Auto-detected Extensions + +The list of auto-detected extensions can be filtered using include and exclude patterns +via the following <>: + +`junit.jupiter.extensions.autodetection.include=`:: + Comma-separated list of _include_ patterns for auto-detected extensions. +`junit.jupiter.extensions.autodetection.exclude=`:: + Comma-separated list of _exclude_ patterns for auto-detected extensions. + +Include patterns are applied _before_ exclude patterns. If both include and exclude +patterns are provided, only extensions that match at least one include pattern and do not +match any exclude pattern will be auto-detected. + +See <> for details on the pattern syntax. + +[[extensions-registration-inheritance]] +==== Extension Inheritance + +Registered extensions are inherited within test class hierarchies with top-down semantics. +Similarly, extensions registered at the class-level are inherited at the method-level. +This applies to all extensions, independent of how they are registered (declaratively or +programmatically). + +This means that extensions registered declaratively via `@ExtendWith` on a superclass will +be registered before extensions registered declaratively via `@ExtendWith` on a subclass. + +Similarly, extensions registered programmatically via `@RegisterExtension` or +`@ExtendWith` on fields in a superclass will be registered before extensions registered +programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless +`@Order` is used to alter that behavior (see <> for details). + +NOTE: A specific extension implementation can only be registered once for a given +extension context and its parent contexts. Consequently, any attempt to register a +duplicate extension implementation will be ignored. + +[[extensions-conditions]] +=== Conditional Test Execution + +`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test +execution_. + +An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to +determine if all the tests it contains should be executed based on the supplied +`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to +determine if a given test method should be executed based on the supplied +`ExtensionContext`. + +When multiple `ExecutionCondition` extensions are registered, a container or test is +disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee +that a condition is evaluated because another extension might have already caused a +container or test to be disabled. In other words, the evaluation works like the +short-circuiting boolean OR operator. + +See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. + +[[extensions-conditions-deactivation]] +==== Deactivating Conditions + +Sometimes it can be useful to run a test suite _without_ certain conditions being active. +For example, you may wish to run tests even if they are annotated with `@Disabled` in +order to see if they are still _broken_. To do this, provide a pattern for the +`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which +conditions should be deactivated (i.e., not evaluated) for the current test run. The +pattern can be supplied as a JVM system property, as a _configuration parameter_ in the +`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform +configuration file (see <> for details). + +For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the +following system property. + +`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` + +[[extensions-conditions-deactivation-patterns]] +===== Pattern Matching Syntax + +Refer to <> for details. + +[[extensions-test-instance-pre-construct-callback]] +=== Test Instance Pre-construct Callback + +`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked +_prior_ to test instances being constructed (by a constructor call or via +`{TestInstanceFactory}`). + +This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful +in combination with other extensions to prepare constructor parameters or keeping track of test +instances and their lifecycle. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-factories]] +=== Test Instance Factories + +`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class +instances. + +Common use cases include acquiring the test instance from a dependency injection +framework or invoking a static factory method to create the test class instance. + +If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ +constructor for the test class to instantiate it, potentially resolving constructor +arguments via registered `ParameterResolver` extensions. + +Extensions that implement `TestInstanceFactory` can be registered on test interfaces, +top-level test classes, or `@Nested` test classes. + +[WARNING] +==== +Registering multiple extensions that implement `TestInstanceFactory` for any single class +will result in an exception being thrown for all tests in that class, in any subclass, +and in any nested class. Note that any `TestInstanceFactory` registered in a superclass +or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is +the user's responsibility to ensure that only a single `TestInstanceFactory` is +registered for any specific test class. +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-post-processing]] +=== Test Instance Post-processing + +`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post +process_ test instances. + +Common use cases include injecting dependencies into the test instance, invoking custom +initialization methods on the test instance, etc. + +For a concrete example, consult the source code for the `{MockitoExtension}` and the +`{SpringExtension}`. + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation or if +you want to <> on the test method level. +==== + +[[extensions-test-instance-pre-destroy-callback]] +=== Test Instance Pre-destroy Callback + +`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process +test instances _after_ they have been used in tests and _before_ they are destroyed. + +Common use cases include cleaning dependencies that have been injected into the +test instance, invoking custom de-initialization methods on the test instance, etc. + +[[extensions-parameter-resolution]] +=== Parameter Resolution + +`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at +runtime. + +If a _test class_ constructor, _test method_, or _lifecycle method_ (see +<>) declares a parameter, the parameter must be _resolved_ at +runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see +`{TestInfoParameterResolver}`) or <>. +Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any +combination thereof. + +If you wish to implement a custom `{ParameterResolver}` that resolves parameters based +solely on the type of the parameter, you may find it convenient to extend the +`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. + +For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, +`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. + +[WARNING] +==== +Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, +looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` +API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` +test class). + +The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore +includes the following convenience methods for correctly looking up annotations on +parameters. Extension authors are strongly encouraged to use these methods instead of +those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. + +* `boolean isAnnotated(Class annotationType)` +* `Optional findAnnotation(Class annotationType)` +* `List findRepeatableAnnotations(Class annotationType)` +==== + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to support injecting test specific data into constructor parameters of the +test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while +resolving constructor parameters, unless the +<> is set to `PER_CLASS`. +==== + +[TIP] +.Parameter resolution for methods called from extensions +==== +Other extensions can also leverage registered `ParameterResolvers` for method and +constructor invocations, using the `{ExecutableInvoker}` available via the +`getExecutableInvoker()` method in the `ExtensionContext`. +==== + +[[extensions-parameter-resolution-conflicts]] +==== Parameter Conflicts + +If multiple implementations of `ParameterResolver` that support the same type are +registered for a test, a `ParameterResolutionException` will be thrown, with a +message to indicate that competing resolvers have been discovered. See the following +example: + +[source,java,indent=0] +.Conflicting parameter resolution due to multiple resolvers claiming support for integers +---- +include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations are applied to different test +methods as shown in the following example, no conflict occurs. + +[source,java,indent=0] +.Fine-grained registration to avoid conflict +---- +include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +---- + +If the conflicting `ParameterResolver` implementations need to be applied to the same test +method, you can implement a custom type or custom annotation as illustrated by +`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. + +[source,java,indent=0] +.Custom type to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +---- + +A custom annotation makes the duplicate type distinguishable from its counterpart: + +[source,java,indent=0] +.Custom annotation to resolve duplicate types +---- +include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +---- + +JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver +attempts to claim their supported types. For example, `{TestInfo}` provides metadata about +tests. See <> for details. Third-party frameworks such +as Spring may also define parameter resolvers. Apply one of the techniques in this section +to resolve any conflicts. + +Parameterized tests are another potential source of conflict. Ensure that tests annotated +with `@ParameterizedTest` are not also annotated with `@Test` and see +<> for more details. + +[[extensions-test-result-processing]] +=== Test Result Processing + +`{TestWatcher}` defines the API for extensions that wish to process the results of _test +method_ executions. Specifically, a `TestWatcher` will be invoked with contextual +information for the following events. + +* `testDisabled`: invoked after a disabled _test method_ has been skipped +* `testSuccessful`: invoked after a _test method_ has completed successfully +* `testAborted`: invoked after a _test method_ has been aborted +* `testFailed`: invoked after a _test method_ has failed + +NOTE: In contrast to the definition of "test method" presented in +<>, in this context _test method_ refers to any `@Test` method +or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). + +Extensions implementing this interface can be registered at the class level, instance +level, or method level. When registered at the class level, a `TestWatcher` will be +invoked for any contained _test method_ including those in `@Nested` classes. When +registered at the method level, a `TestWatcher` will only be invoked for the _test method_ +for which it was registered. + +[WARNING] +==== +If a `TestWatcher` is registered via a non-static (instance) field – for example, using +`@RegisterExtension` – and the test class is configured with +`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the +`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for +example, `@RepeatedTest` or `@ParameterizedTest`). + +To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is +therefore recommended that the `TestWatcher` be registered at the class level with +`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. +==== + +If there is a failure at the class level — for example, an exception thrown by a +`@BeforeAll` method — no test results will be reported. Similarly, if the test class is +disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be +reported. + +In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely +influence the execution of tests. Consequently, any exception thrown by a method in the +`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate +or fail test execution. + +[WARNING] +==== +Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the +provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are +invoked (see <>). You can use the parent context's `Store` to +work with such resources. +==== + +[[extensions-lifecycle-callbacks]] +=== Test Lifecycle Callbacks + +The following interfaces define the APIs for extending tests at various points in the +test execution lifecycle. Consult the following sections for examples and the Javadoc for +each of these interfaces in the `{extension-api-package}` package for further details. + +* `{BeforeAllCallback}` +** `{BeforeClassTemplateInvocationCallback}` (only applicable for + <>) +*** `{BeforeEachCallback}` +**** `{BeforeTestExecutionCallback}` +**** `{AfterTestExecutionCallback}` +*** `{AfterEachCallback}` +** `{AfterClassTemplateInvocationCallback}` (only applicable for + <>) +* `{AfterAllCallback}` + +.Implementing Multiple Extension APIs +NOTE: Extension developers may choose to implement any number of these interfaces +within a single extension. Consult the source code of the `{SpringExtension}` for a +concrete example. + +[[extensions-lifecycle-callbacks-before-after-execution]] +==== Before and After Test Execution Callbacks + +`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for +`Extensions` that wish to add behavior that will be executed _immediately before_ and +_immediately after_ a test method is executed, respectively. As such, these callbacks are +well suited for timing, tracing, and similar use cases. If you need to implement +callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement +`BeforeEachCallback` and `AfterEachCallback` instead. + +The following example shows how to use these callbacks to calculate and log the execution +time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` +and `AfterTestExecutionCallback` in order to time and log the test execution. + +[[extensions-lifecycle-callbacks-timing-extension]] +[source,java,indent=0] +.An extension that times and logs the execution of test methods +---- +include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +---- + +Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, +its tests will have this timing applied when they execute. + +[source,java,indent=0] +.A test class that uses the example TimingExtension +---- +include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +---- + +The following is an example of the logging produced when `TimingExtensionTests` is run. + +.... +INFO: Method [sleep20ms] took 24 ms. +INFO: Method [sleep50ms] took 53 ms. +.... + +[[extensions-exception-handling]] +=== Exception Handling + +Exceptions thrown during the test execution may be intercepted and handled accordingly +before propagating further, so that certain actions like error logging or resource releasing +may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that +wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` +and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, +`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. + +The following example shows an extension which will swallow all instances of `IOException` +but rethrow any other type of exception. + +[source,java,indent=0] +.An exception handling extension that filters IOExceptions in test execution +---- +include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +---- + +Another example shows how to record the state of an application under test exactly at +the point of unexpected exception being thrown during setup and cleanup. Note that unlike +relying on lifecycle callbacks, which may or may not be executed depending on the test +status, this solution guarantees execution immediately after failing `@BeforeAll`, +`@BeforeEach`, `@AfterEach` or `@AfterAll`. + +[source,java,indent=0] +.An exception handling extension that records application state on error +---- +include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +---- + +Multiple execution exception handlers may be invoked for the same lifecycle method in +order of declaration. If one of the handlers swallows the handled exception, subsequent +ones will not be executed, and no failure will be propagated to JUnit engine, as if the +exception was never thrown. Handlers may also choose to rethrow the exception or throw +a different one, potentially wrapping the original. + +Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle +exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, +while handlers for `BeforeEach` and `AfterEach` may be also registered for individual +test methods. + +[source,java,indent=0] +.Registering multiple exception handling extensions +---- +include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +---- + +[[extensions-preinterrupt-callback]] +=== Pre-Interrupt Callback + +`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on +timeouts before the `Thread.interrupt()` is called. + +Please refer to <> for additional information. + + +[[extensions-intercepting-invocations]] +=== Intercepting Invocations + +`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to +test code. + +The following example shows an extension that executes all test methods in Swing's Event +Dispatch Thread. + +[source,java,indent=0] +.An extension that executes tests in a user-defined thread +---- +include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +---- + +[NOTE] +.Accessing the test-scoped `ExtensionContext` +==== +You may override the `getTestInstantiationExtensionContextScope(...)` method to return +`TEST_METHOD` to make test-specific data available to your extension implementation of +`interceptTestClassConstructor` or if you want to <> +on the test method level. +==== + +[[extensions-class-templates]] +=== Providing Invocation Contexts for Class Templates + +A `{ClassTemplate}` class can only be executed when at least one +`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is +responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. +Each context may specify a custom display name and a list of additional extensions that +will only be used for the next invocation of the `{ClassTemplate}`. + +The following example shows how to write a class template as well as how to register +and implement a `{ClassTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A class template with accompanying extension +---- +include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +---- + +In this example, the class template will be invoked twice, meaning all test methods in +the class template will be executed twice. The display names of the invocations will be +`apple` and `banana` as specified by the invocation context. Each invocation registers a +custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The +output when using the `ConsoleLauncher` is as follows. + +.... +└─ ClassTemplateDemo ✔ + ├─ apple ✔ + │ ├─ notNull() ✔ + │ └─ wellKnown() ✔ + └─ banana ✔ + ├─ notNull() ✔ + └─ wellKnown() ✔ +.... + +The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of _all_ test +methods in a test class albeit in different contexts — for example, with different +parameters, by preparing the test class instance differently, or multiple times without +modifying the context. +Please refer to the implementations of +<> which uses this extension +point to provide its functionality. + +[[extensions-test-templates]] +=== Providing Invocation Contexts for Test Templates + +A `{TestTemplate}` method can only be executed when at least one +`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible +for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may +specify a custom display name and a list of additional extensions that will only be used +for the next invocation of the `{TestTemplate}` method. + +The following example shows how to write a test template as well as how to register and +implement a `{TestTemplateInvocationContextProvider}`. + +[source,java,indent=0] +.A test template with accompanying extension +---- +include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +---- + +In this example, the test template will be invoked twice. The display names of the +invocations will be `apple` and `banana` as specified by the invocation context. Each +invocation registers a custom `{ParameterResolver}` which is used to resolve the method +parameter. The output when using the `ConsoleLauncher` is as follows. + +.... +└─ testTemplate(String) ✔ + ├─ apple ✔ + └─ banana ✔ +.... + +The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for +implementing different kinds of tests that rely on repetitive invocation of a test-like +method albeit in different contexts — for example, with different parameters, by preparing +the test class instance differently, or multiple times without modifying the context. +Please refer to the implementations of <> or +<> which use this extension point +to provide their functionality. + +[[extensions-keeping-state]] +=== Keeping State in Extensions + +Usually, an extension is instantiated only once. So the question becomes relevant: How do +you keep the state from one invocation of an extension to the next? The +`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. +Extensions may put values into a store for later retrieval. + +TIP: See the `<>` for an +example of using the `Store` with a method-level scope. + +.The `ExtensionContext` and `Store` hierarchy +image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] + +As illustrated by the diagram above, stores are hierarchical in nature. When looking up a +value, if no value is stored in the current `ExtensionContext` for the supplied key, the +stores of the context's ancestors will be queried for a value with the same key in the +`Namespace` used to create this store. The root `ExtensionContext` represents the engine +level so its `Store` may be used to store or cache values that are used by multiple test +classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even +that and access the stores on the level of the current `{LauncherExecutionRequest}` or +`{LauncherSession}` which can be used to share data across test engines or inject data +from a registered +<>, +respectively. Please consult the Javadoc of `{ExtensionContext}`, +`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. + +[[extensions-keeping-state-autocloseable-support]] +[NOTE] +.Resource management via `_AutoCloseable_` +==== +An extension context store is bound to its extension context lifecycle. When an extension +context lifecycle ends it closes its associated store. + +All stored values that are instances of `AutoCloseable` are notified by an invocation of +their `close()` method in the inverse order they were added in (unless the +`junit.jupiter.extensions.store.close.autocloseable.enabled` +<> is set to `false`). + +Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still +available for backward compatibility. +==== + +An example implementation of `AutoCloseable` is shown below, using an `HttpServer` +resource. + +[source,java,indent=0] +.`_HttpServer_` resource implementing `_AutoCloseable_` +---- +include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +---- + +This resource can then be stored in the desired `ExtensionContext`. It may be stored at +class or method level, if desired, but this may add unnecessary overhead for this type of +resource. For this example it might be prudent to store it at root level and instantiate +it lazily to ensure it's only created once per test run and reused across different test +classes and methods. + +[source,java,indent=0] +.Lazily storing in root context with `_Store.computeIfAbsent_` +---- +include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +---- + +[source,java,indent=0] +.A test case using the `_HttpServerExtension_` +---- +include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +---- + +[[extensions-keeping-state-autocloseable-migration]] +[TIP] +.Migration Note for Resource Cleanup +==== +The framework automatically closes resources stored in the `ExtensionContext.Store` that +implement `AutoCloseable`. In versions prior to 5.13, only resources implementing +`Store.CloseableResource` were automatically closed. + +If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and +earlier versions and your extension stores resources that need to be cleaned up, you +should implement both interfaces: + +[source,java,indent=0] +---- +public class MyResource implements Store.CloseableResource, AutoCloseable { + @Override + public void close() throws Exception { + // Resource cleanup code + } +} +---- + +This ensures that your resource will be properly closed regardless of which JUnit Jupiter +version is being used. +==== + +[[extensions-supported-utilities]] +=== Supported Utilities in Extensions + +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. + +[[extensions-supported-utilities-annotations]] +==== Annotation Support + +`AnnotationSupport` provides static utility methods that operate on annotated elements +(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). +These include methods to check whether an element is annotated or meta-annotated with a +particular annotation, to search for specific annotations, and to find annotated methods +and fields in a class or interface. Some of these methods search on implemented +interfaces and within class hierarchies to find annotations. Consult the Javadoc for +`{AnnotationSupport}` for further details. + +NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, +use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. + +NOTE: See also: <> + +[[extensions-supported-utilities-classes]] +==== Class Support + +`ClassSupport` provides static utility methods for working with classes (i.e., instances +of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. + +[[extensions-supported-utilities-reflection]] +==== Reflection Support + +`ReflectionSupport` provides static utility methods that augment the standard JDK +reflection and class-loading mechanisms. These include methods to scan the classpath in +search of classes matching specified predicates, to load and create new instances of a +class, and to find and invoke methods. Some of these methods traverse class hierarchies +to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further +details. + +NOTE: See also: <> + +[[extensions-supported-utilities-modifier]] +==== Modifier Support + +`ModifierSupport` provides static utility methods for working with member and class +modifiers -- for example, to determine if a member is declared as `public`, `private`, +`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further +details. + +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. + +[[extensions-supported-utilities-search-semantics]] +==== Field and Method Search Semantics + +Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that +traverse type hierarchies to locate matching fields and methods – for example, +`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. + +The field and method search algorithms adhere to standard Java semantics regarding whether +a given field or method is visible or overridden according to the rules of the Java +language. + +[[extensions-execution-order]] +=== Relative Execution Order of User Code and Extensions + +When executing a test class that contains one or more test methods, a number of extension +callbacks are called in addition to the user-supplied test and lifecycle methods. + +NOTE: See also: <> + +[[extensions-execution-order-overview]] +==== User and Extension Code + +The following diagram illustrates the relative order of user-supplied code and extension +code. User-supplied test and lifecycle methods are shown in orange, with callback code +implemented by extensions shown in blue. The grey box denotes the execution of a single +test method and will be repeated for every test method in the test class. + +[[extensions-execution-order-diagram]] +.User code and extension code +image::extensions_lifecycle.png[] + +The following table further explains the sixteen steps in the +<> diagram. + +. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + +extension code executed before all tests of the container are executed +. *annotation* `*org.junit.jupiter.api.BeforeAll*` + +user code executed before all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeAll` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + +extension code executed before each class template invocation is executed (only applicable +if the test class is a <>) +. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + +extension code executed before each test is executed +. *annotation* `*org.junit.jupiter.api.BeforeEach*` + +user code executed before each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleBeforeEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@BeforeEach` methods +. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + +extension code executed immediately before a test is executed +. *annotation* `*org.junit.jupiter.api.Test*` + +user code of the actual test method +. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + +extension code for handling exceptions thrown during a test +. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + +extension code executed immediately after test execution and its corresponding exception handlers +. *annotation* `*org.junit.jupiter.api.AfterEach*` + +user code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterEachMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterEach` methods +. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + +extension code executed after each test is executed +. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + +extension code executed after each class template invocation is executed (only applicable +if the test class is a <>) +. *annotation* `*org.junit.jupiter.api.AfterAll*` + +user code executed after all tests of the container are executed +. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler +#handleAfterAllMethodExecutionException*` + +extension code for handling exceptions thrown from `@AfterAll` methods +. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + +extension code executed after all tests of the container are executed + +In the simplest case only the actual test method will be executed (step 9); all other +steps are optional depending on the presence of user code or extension support for the +corresponding lifecycle callback. For further details on the various lifecycle callbacks +please consult the respective Javadoc for each annotation and extension. + +All invocations of user code methods in the above table can additionally be intercepted +by implementing <>. + +[[extensions-execution-order-wrapping-behavior]] +==== Wrapping Behavior of Callbacks + +JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions +that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, +`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, +`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and +`AfterTestExecutionCallback`. + +That means that, given two extensions `Extension1` and `Extension2` with `Extension1` +registered before `Extension2`, any "before" callbacks implemented by `Extension1` are +guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. +Similarly, given the two same two extensions registered in the same order, any "after" +callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" +callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ +`Extension2`. + +JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies +for user-supplied _lifecycle methods_ (see <>). + +* `@BeforeAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed + **before** `@BeforeAll` methods in subclasses. +** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@BeforeAll` methods from an interface will be executed + **before** `@BeforeAll` methods in the class that implements the interface. +* `@AfterAll` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed + **after** `@AfterAll` methods in subclasses. +** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they + are not _overridden_, and `@AfterAll` methods from an interface will be executed + **after** `@AfterAll` methods in the class that implements the interface. +* `@BeforeEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed + **before** `@BeforeEach` methods in subclasses. +** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@BeforeEach` default methods will be executed + **before** `@BeforeEach` methods in the class that implements the interface. +* `@AfterEach` methods are inherited from superclasses as long as they are not + _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed + **after** `@AfterEach` methods in subclasses. +** Similarly, `@AfterEach` methods declared as interface default methods are inherited as + long as they are not _overridden_, and `@AfterEach` default methods will be executed + **after** `@AfterEach` methods in the class that implements the interface. + +The following examples demonstrate this behavior. Please note that the examples do not +actually do anything realistic. Instead, they mimic common scenarios for testing +interactions with the database. All methods imported statically from the `Logger` class +log contextual information in order to help us better understand the execution order of +user-supplied callback methods and callback methods in extensions. + +[source,java,indent=0] +.Extension1 +---- +include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +---- + +[source,java,indent=0] +.Extension2 +---- +include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +---- + +[source,java,indent=0] +.AbstractDatabaseTests +---- +include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +---- + +[source,java,indent=0] +.DatabaseTestsDemo +---- +include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +---- + +When the `DatabaseTestsDemo` test class is executed, the following is logged. + +---- +@BeforeAll AbstractDatabaseTests.createDatabase() +@BeforeAll DatabaseTestsDemo.beforeAll() + Extension1.beforeEach() + Extension2.beforeEach() + @BeforeEach AbstractDatabaseTests.connectToDatabase() + @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() + @Test DatabaseTestsDemo.testDatabaseFunctionality() + @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() + @AfterEach AbstractDatabaseTests.disconnectFromDatabase() + Extension2.afterEach() + Extension1.afterEach() +@BeforeAll DatabaseTestsDemo.afterAll() +@AfterAll AbstractDatabaseTests.destroyDatabase() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] + +JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods +that are declared within a _single_ test class or test interface. It may at times appear +that JUnit Jupiter invokes such methods in alphabetical order. However, that is not +precisely true. The ordering is analogous to the ordering for `@Test` methods within a +single test class. + +[NOTE] +==== +Lifecycle methods that are declared within a _single_ test class or test interface will be +ordered using an algorithm that is deterministic but intentionally non-obvious. This +ensures that subsequent runs of a test suite execute lifecycle methods in the same order, +thereby allowing for repeatable builds. +==== + +In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle +methods declared within a single test class or test interface. + +The following example demonstrates this behavior. Specifically, the lifecycle method +configuration is _broken_ due to the order in which the locally declared lifecycle methods +are executed. + +* Test data is inserted _before_ the database connection has been opened, which results in + a failure to connect to the database. +* The database connection is closed _before_ deleting the test data, which results in a + failure to connect to the database. + +[source,java,indent=0] +.BrokenLifecycleMethodConfigDemo +---- +include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +---- + +When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. + +---- +Extension1.beforeEach() +Extension2.beforeEach() + @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() + @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() + @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() + @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() + @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() +Extension2.afterEach() +Extension1.afterEach() +---- + +The following sequence diagram helps to shed further light on what actually goes on within +the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. + +//// +PNG generated using ZenUML: https://app.zenuml.com + +See corresponding *.txt file in images folder for the source. +//// +image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] + +[TIP] +==== +Due to the aforementioned behavior, the JUnit Team recommends that developers declare at +most one of each type of _lifecycle method_ (see <>) per test +class or test interface unless there are no dependencies between such lifecycle methods. +==== From 27057c1161d95ccb9881e48fca1b55812f49018a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:13 +0100 Subject: [PATCH 28/57] Migrate extensions.adoc sections to Antora --- .../conditional-test-execution.adoc | 1215 ---------------- .../pages/extensions/exception-handling.adoc | 1209 ---------------- .../extensions/intercepting-invocations.adoc | 1233 ---------------- .../keeping-state-in-extensions.adoc | 1161 --------------- .../ROOT/pages/extensions/overview.adoc | 1250 ----------------- .../extensions/parameter-resolution.adoc | 1151 --------------- .../extensions/pre-interrupt-callback.adoc | 1248 ---------------- ...vocation-contexts-for-class-templates.adoc | 1214 ---------------- ...nvocation-contexts-for-test-templates.adoc | 1220 ---------------- .../extensions/registering-extensions.adoc | 923 ------------ ...ion-order-of-user-code-and-extensions.adoc | 1018 -------------- .../supported-utilities-in-extensions.adoc | 1186 ---------------- .../extensions/test-instance-factories.adoc | 1223 ---------------- .../test-instance-post-processing.adoc | 1237 ---------------- .../test-instance-pre-construct-callback.adoc | 1238 ---------------- .../test-instance-pre-destroy-callback.adoc | 1248 ---------------- .../extensions/test-lifecycle-callbacks.adoc | 1197 ---------------- .../extensions/test-result-processing.adoc | 1204 ---------------- 18 files changed, 21375 deletions(-) diff --git a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc index 213721b04e2c..5dfa63cccd3c 100644 --- a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc @@ -1,350 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - [[extensions-conditions]] === Conditional Test Execution @@ -387,871 +40,3 @@ following system property. Refer to <> for details. -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/exception-handling.adoc b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc index 213721b04e2c..a6629a46d72b 100644 --- a/documentation/modules/ROOT/pages/extensions/exception-handling.adoc +++ b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc @@ -1,693 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - [[extensions-exception-handling]] === Exception Handling @@ -736,522 +46,3 @@ test methods. include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ---- -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc index 213721b04e2c..590543f1a86d 100644 --- a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc +++ b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc @@ -1,750 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - [[extensions-intercepting-invocations]] === Intercepting Invocations @@ -769,489 +22,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to on the test method level. ==== -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc index 213721b04e2c..51cc8a553c92 100644 --- a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc @@ -1,854 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - [[extensions-keeping-state]] === Keeping State in Extensions @@ -945,313 +94,3 @@ This ensures that your resource will be properly closed regardless of which JUni version is being used. ==== -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/overview.adoc b/documentation/modules/ROOT/pages/extensions/overview.adoc index 213721b04e2c..8d2f8e4112b5 100644 --- a/documentation/modules/ROOT/pages/extensions/overview.adoc +++ b/documentation/modules/ROOT/pages/extensions/overview.adoc @@ -1,9 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - [[extensions-overview]] === Overview @@ -11,1247 +5,3 @@ In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension po JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the `Extension` API. Note, however, that `Extension` itself is just a marker interface. -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc index 213721b04e2c..6e92e3ab863d 100644 --- a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc +++ b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc @@ -1,474 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - [[extensions-parameter-resolution]] === Parameter Resolution @@ -575,683 +104,3 @@ Parameterized tests are another potential source of conflict. Ensure that tests with `@ParameterizedTest` are not also annotated with `@Test` and see <> for more details. -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc index 213721b04e2c..5d34a551de65 100644 --- a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc @@ -1,741 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - [[extensions-preinterrupt-callback]] === Pre-Interrupt Callback @@ -745,513 +7,3 @@ timeouts before the `Thread.interrupt()` is called. Please refer to <> for additional information. -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc index 213721b04e2c..7b0ac9babcab 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc @@ -1,774 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - [[extensions-class-templates]] === Providing Invocation Contexts for Class Templates @@ -812,446 +41,3 @@ Please refer to the implementations of <> which uses this extension point to provide its functionality. -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc index 213721b04e2c..4a4d22c5ca6c 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc @@ -1,817 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - [[extensions-test-templates]] === Providing Invocation Contexts for Test Templates @@ -849,409 +35,3 @@ Please refer to the implementations of <> or <> which use this extension point to provide their functionality. -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc index 213721b04e2c..3dd520298948 100644 --- a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc @@ -1,16 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - [[extensions-registration]] === Registering Extensions @@ -345,913 +332,3 @@ NOTE: A specific extension implementation can only be registered once for a give extension context and its parent contexts. Consequently, any attempt to register a duplicate extension implementation will be ignored. -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc index 213721b04e2c..8e5da6d38612 100644 --- a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc @@ -1,1021 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - [[extensions-execution-order]] === Relative Execution Order of User Code and Extensions diff --git a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc index 213721b04e2c..0bd27a99d5a2 100644 --- a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc @@ -1,950 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - [[extensions-supported-utilities]] === Supported Utilities in Extensions @@ -1016,242 +69,3 @@ The field and method search algorithms adhere to standard Java semantics regardi a given field or method is visible or overridden according to the rules of the Java language. -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc index 213721b04e2c..ff042496c539 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc @@ -1,411 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - [[extensions-test-instance-factories]] === Test Instance Factories @@ -440,818 +32,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to you want to <> on the test method level. ==== -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc index 213721b04e2c..84dbc3bca5f3 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc @@ -1,445 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - [[extensions-test-instance-post-processing]] === Test Instance Post-processing @@ -460,798 +18,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to you want to <> on the test method level. ==== -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc index 213721b04e2c..65a185ef79aa 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc @@ -1,392 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - [[extensions-test-instance-pre-construct-callback]] === Test Instance Pre-construct Callback @@ -406,852 +17,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to you want to <> on the test method level. ==== -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc index 213721b04e2c..acda444fb67a 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc @@ -1,465 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - [[extensions-test-instance-pre-destroy-callback]] === Test Instance Pre-destroy Callback @@ -469,789 +7,3 @@ test instances _after_ they have been used in tests and _before_ they are destro Common use cases include cleaning dependencies that have been injected into the test instance, invoking custom de-initialization methods on the test instance, etc. -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc index 213721b04e2c..d34b10954a51 100644 --- a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc @@ -1,633 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - -[[extensions-test-result-processing]] -=== Test Result Processing - -`{TestWatcher}` defines the API for extensions that wish to process the results of _test -method_ executions. Specifically, a `TestWatcher` will be invoked with contextual -information for the following events. - -* `testDisabled`: invoked after a disabled _test method_ has been skipped -* `testSuccessful`: invoked after a _test method_ has completed successfully -* `testAborted`: invoked after a _test method_ has been aborted -* `testFailed`: invoked after a _test method_ has failed - -NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method -or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). - -Extensions implementing this interface can be registered at the class level, instance -level, or method level. When registered at the class level, a `TestWatcher` will be -invoked for any contained _test method_ including those in `@Nested` classes. When -registered at the method level, a `TestWatcher` will only be invoked for the _test method_ -for which it was registered. - -[WARNING] -==== -If a `TestWatcher` is registered via a non-static (instance) field – for example, using -`@RegisterExtension` – and the test class is configured with -`@TestInstance(Lifecycle.PER_METHOD)` semantics (which is the default lifecycle mode), the -`TestWatcher` will **not** be invoked with events for `@TestTemplate` methods (for -example, `@RepeatedTest` or `@ParameterizedTest`). - -To ensure that a `TestWatcher` is invoked for all _test methods_ in a given class, it is -therefore recommended that the `TestWatcher` be registered at the class level with -`@ExtendWith` or via a `static` field with `@RegisterExtension` or `@ExtendWith`. -==== - -If there is a failure at the class level — for example, an exception thrown by a -`@BeforeAll` method — no test results will be reported. Similarly, if the test class is -disabled via an `ExecutionCondition` — for example, `@Disabled` — no test results will be -reported. - -In contrast to other Extension APIs, a `TestWatcher` is not permitted to adversely -influence the execution of tests. Consequently, any exception thrown by a method in the -`TestWatcher` API will be logged at `WARNING` level and will not be allowed to propagate -or fail test execution. - -[WARNING] -==== -Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the -provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to -work with such resources. -==== - [[extensions-lifecycle-callbacks]] === Test Lifecycle Callbacks @@ -688,570 +58,3 @@ INFO: Method [sleep20ms] took 24 ms. INFO: Method [sleep50ms] took 53 ms. .... -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== diff --git a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc index 213721b04e2c..24e3ddf16680 100644 --- a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc @@ -1,580 +1,3 @@ -:testDir: ../../../../src/test/java -:kotlinTestDir: ../../../../src/test/kotlin - -[[extensions]] -== Extension Model - -[[extensions-overview]] -=== Overview - -In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in -JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the -`Extension` API. Note, however, that `Extension` itself is just a marker interface. - -[[extensions-registration]] -=== Registering Extensions - -Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. - -[[extensions-registration-declarative]] -==== Declarative Extension Registration - -Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to -register. `@ExtendWith` may also be declared on fields or on parameters in test class -constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and -`@AfterEach` lifecycle methods. - -For example, to register a `WebServerExtension` for a particular test method, you would -annotate the test method as follows. We assume the `WebServerExtension` starts a local web -server and injects the server's URL into parameters annotated with `@WebServerUrl`. - -[source,java,indent=0] ----- -@Test -@ExtendWith(WebServerExtension.class) -void getProductList(@WebServerUrl String serverUrl) { - WebClient webClient = new WebClient(); - // Use WebClient to connect to web server using serverUrl and verify response - assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus()); -} ----- - -To register the `WebServerExtension` for all tests in a particular class and its -subclasses, you would annotate the test class as follows. - -[source,java,indent=0] ----- -@ExtendWith(WebServerExtension.class) -class MyTests { - // ... -} ----- - -Multiple extensions can be registered together like this: - -[source,java,indent=0] ----- -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -class MyFirstTests { - // ... -} ----- - -As an alternative, multiple extensions can be registered separately like this: - -[source,java,indent=0] ----- -@ExtendWith(DatabaseExtension.class) -@ExtendWith(WebServerExtension.class) -class MySecondTests { - // ... -} ----- - -[TIP] -.Extension Registration Order -==== -Extensions registered declaratively via `@ExtendWith` at the class level, method level, or -parameter level will be executed in the order in which they are declared in the source -code. For example, the execution of tests in both `MyFirstTests` and `MySecondTests` will -be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly that order**. -==== - -If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a -_meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` -can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. - -[source,java,indent=0] ----- -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@ExtendWith({ DatabaseExtension.class, WebServerExtension.class }) -public @interface DatabaseAndWebServerExtension { -} ----- - -The above examples demonstrate how `@ExtendWith` can be applied at the class level or at -the method level; however, for certain use cases it makes sense for an extension to be -registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` which generates random numbers that can be injected into a field or -via a parameter in a constructor, test method, or lifecycle method. If the extension -provides a `@Random` annotation that is meta-annotated with -`@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used -transparently as in the following `RandomNumberDemo` example. - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/Random.java[tags=user_guide] ----- - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] ----- - -[[extensions-RandomNumberExtension]] -The following code listing provides an example of how one might choose to implement such a -`RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for -example, the random number generation support is limited to integers; it uses -`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is -important to note which extension APIs are implemented and for what reasons. - -Specifically, `RandomNumberExtension` implements the following extension APIs: - -- `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection -- `ParameterResolver`: to support constructor and method injection - -[source,java,indent=0] ----- -include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] ----- - -[TIP] -.Extension Registration Order for `@ExtendWith` on Fields -==== -Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative -to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is -deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be -inherited. - -See <> for details. -==== - -NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for -`@RegisterExtension` fields also applies to `@ExtendWith` fields. - -[[extensions-registration-programmatic]] -==== Programmatic Extension Registration - -Developers can register extensions _programmatically_ by annotating fields in test classes -with `{RegisterExtension}`. - -When an extension is registered _declaratively_ via -<>, it can typically only be configured -via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it -can be configured _programmatically_ -- for example, in order to pass arguments to the -extension's constructor, a static factory method, or a builder API. - -[[extensions-registration-programmatic-order]] -[TIP] -.Extension Registration Order -==== -By default, extensions registered programmatically via `@RegisterExtension` or -declaratively via `@ExtendWith` on fields will be ordered using an algorithm that is -deterministic but intentionally nonobvious. This ensures that subsequent runs of a test -suite execute extensions in the same order, thereby allowing for repeatable builds. -However, there are times when extensions need to be registered in an explicit order. To -achieve that, annotate `@RegisterExtension` fields or `@ExtendWith` fields with `{Order}`. - -Any `@RegisterExtension` field or `@ExtendWith` field not annotated with `@Order` will be -ordered using the _default_ order which has a value of `Integer.MAX_VALUE / 2`. This -allows `@Order` annotated extension fields to be explicitly ordered before or after -non-annotated extension fields. Extensions with an explicit order value less than the -default order value will be registered before non-annotated extensions. Similarly, -extensions with an explicit order value greater than the default order value will be -registered after non-annotated extensions. For example, assigning an extension an explicit -order value that is greater than the default order value allows _before_ callback -extensions to be registered last and _after_ callback extensions to be registered first, -relative to other programmatically registered extensions. -==== - -[TIP] -.Extension Inheritance -==== -Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses -will be inherited. - -See <> for details. -==== - -NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be -either `static` or non-static. - -[[extensions-registration-programmatic-static-fields]] -===== Static Fields - -If a `@RegisterExtension` field is `static`, the extension will be registered after -extensions that are registered at the class level via `@ExtendWith`. Such _static -extensions_ are not limited in which extension APIs they can implement. Extensions -registered via static fields may therefore implement class-level and instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, -`TestInstancePostProcessor`, and `TestInstancePreDestroyCallback` as well as method-level -extension APIs such as `BeforeEachCallback`, etc. - -In the following example, the `server` field in the test class is initialized -programmatically by using a builder pattern supported by the `WebServerExtension`. The -configured `WebServerExtension` will be automatically registered as an extension at the -class level -- for example, in order to start the server before all tests in the class -and then stop the server after all tests in the class have completed. In addition, static -lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@BeforeEach`, -`@AfterEach`, and `@Test` methods can access the instance of the extension via the -`server` field if necessary. - -[source,java,indent=0] -.Registering an extension via a static field in Java ----- -include::{testDir}/example/registration/WebServerDemo.java[tags=user_guide] ----- - -[[extensions-registration-programmatic-static-fields-kotlin]] -====== Static Fields in Kotlin - -The Kotlin programming language does not have the concept of a `static` field. However, -the compiler can be instructed to generate a `private static` field using the `@JvmStatic` -annotation in Kotlin. If you want the Kotlin compiler to generate a `public static` field, -you can use the `@JvmField` annotation instead. - -The following example is a version of the `WebServerDemo` from the previous section that -has been ported to Kotlin. - -[source,kotlin,indent=0] -.Registering an extension via a static field in Kotlin ----- -include::{kotlinTestDir}/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ----- - -[[extensions-registration-programmatic-instance-fields]] -===== Instance Fields - -If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension -will be registered after the test class has been instantiated and after each registered -`TestInstancePostProcessor` has been given a chance to post-process the test instance -(potentially injecting the instance of the extension to be used into the annotated -field). Thus, if such an _instance extension_ implements class-level or instance-level -extension APIs such as `BeforeAllCallback`, `AfterAllCallback`, or -`TestInstancePostProcessor`, those APIs will not be honored. Instance extensions will be -registered _before_ extensions that are registered at the method level via `@ExtendWith`. - -In the following example, the `docs` field in the test class is initialized -programmatically by invoking a custom `lookUpDocsDir()` method and supplying the result -to the static `forPath()` factory method in the `DocumentationExtension`. The configured -`DocumentationExtension` will be automatically registered as an extension at the method -level. In addition, `@BeforeEach`, `@AfterEach`, and `@Test` methods can access the -instance of the extension via the `docs` field if necessary. - -[source,java,indent=0] -.An extension registered via an instance field ----- -include::{testDir}/example/registration/DocumentationDemo.java[tags=user_guide] ----- - -[[extensions-registration-automatic]] -==== Automatic Extension Registration - -In addition to <> -and <> support -using annotations, JUnit Jupiter also supports _global extension registration_ via Java's -`{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and -automatically registered based on what is available in the classpath. - -Specifically, a custom extension can be registered by supplying its fully qualified class -name in a file named `org.junit.jupiter.api.extension.Extension` within the -`/META-INF/services` folder in its enclosing JAR file. - -[[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection - -Auto-detection is an advanced feature and is therefore not enabled by default. To enable -it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to -`true`. This can be supplied as a JVM system property, as a _configuration parameter_ in -the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to enable auto-detection of extensions, you can start your JVM with the -following system property. - -`-Djunit.jupiter.extensions.autodetection.enabled=true` - -When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` mechanism -will be added to the extension registry after JUnit Jupiter's global extensions (e.g., -support for `TestInfo`, `TestReporter`, etc.). - -[[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions - -The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: - -`junit.jupiter.extensions.autodetection.include=`:: - Comma-separated list of _include_ patterns for auto-detected extensions. -`junit.jupiter.extensions.autodetection.exclude=`:: - Comma-separated list of _exclude_ patterns for auto-detected extensions. - -Include patterns are applied _before_ exclude patterns. If both include and exclude -patterns are provided, only extensions that match at least one include pattern and do not -match any exclude pattern will be auto-detected. - -See <> for details on the pattern syntax. - -[[extensions-registration-inheritance]] -==== Extension Inheritance - -Registered extensions are inherited within test class hierarchies with top-down semantics. -Similarly, extensions registered at the class-level are inherited at the method-level. -This applies to all extensions, independent of how they are registered (declaratively or -programmatically). - -This means that extensions registered declaratively via `@ExtendWith` on a superclass will -be registered before extensions registered declaratively via `@ExtendWith` on a subclass. - -Similarly, extensions registered programmatically via `@RegisterExtension` or -`@ExtendWith` on fields in a superclass will be registered before extensions registered -programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). - -NOTE: A specific extension implementation can only be registered once for a given -extension context and its parent contexts. Consequently, any attempt to register a -duplicate extension implementation will be ignored. - -[[extensions-conditions]] -=== Conditional Test Execution - -`{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test -execution_. - -An `ExecutionCondition` is _evaluated_ for each container (e.g., a test class) to -determine if all the tests it contains should be executed based on the supplied -`ExtensionContext`. Similarly, an `ExecutionCondition` is _evaluated_ for each test to -determine if a given test method should be executed based on the supplied -`ExtensionContext`. - -When multiple `ExecutionCondition` extensions are registered, a container or test is -disabled as soon as one of the conditions returns _disabled_. Thus, there is no guarantee -that a condition is evaluated because another extension might have already caused a -container or test to be disabled. In other words, the evaluation works like the -short-circuiting boolean OR operator. - -See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. - -[[extensions-conditions-deactivation]] -==== Deactivating Conditions - -Sometimes it can be useful to run a test suite _without_ certain conditions being active. -For example, you may wish to run tests even if they are annotated with `@Disabled` in -order to see if they are still _broken_. To do this, provide a pattern for the -`junit.jupiter.conditions.deactivate` _configuration parameter_ to specify which -conditions should be deactivated (i.e., not evaluated) for the current test run. The -pattern can be supplied as a JVM system property, as a _configuration parameter_ in the -`LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). - -For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the -following system property. - -`-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` - -[[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax - -Refer to <> for details. - -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback - -`{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked -_prior_ to test instances being constructed (by a constructor call or via -`{TestInstanceFactory}`). - -This extension provides a symmetric call to `{TestInstancePreDestroyCallback}` and is useful -in combination with other extensions to prepare constructor parameters or keeping track of test -instances and their lifecycle. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-factories]] -=== Test Instance Factories - -`{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class -instances. - -Common use cases include acquiring the test instance from a dependency injection -framework or invoking a static factory method to create the test class instance. - -If no `TestInstanceFactory` is registered, the framework will invoke the _sole_ -constructor for the test class to instantiate it, potentially resolving constructor -arguments via registered `ParameterResolver` extensions. - -Extensions that implement `TestInstanceFactory` can be registered on test interfaces, -top-level test classes, or `@Nested` test classes. - -[WARNING] -==== -Registering multiple extensions that implement `TestInstanceFactory` for any single class -will result in an exception being thrown for all tests in that class, in any subclass, -and in any nested class. Note that any `TestInstanceFactory` registered in a superclass -or _enclosing_ class (i.e., in the case of a `@Nested` test class) is _inherited_. It is -the user's responsibility to ensure that only a single `TestInstanceFactory` is -registered for any specific test class. -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing - -`{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post -process_ test instances. - -Common use cases include injecting dependencies into the test instance, invoking custom -initialization methods on the test instance, etc. - -For a concrete example, consult the source code for the `{MockitoExtension}` and the -`{SpringExtension}`. - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. -==== - -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback - -`{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process -test instances _after_ they have been used in tests and _before_ they are destroyed. - -Common use cases include cleaning dependencies that have been injected into the -test instance, invoking custom de-initialization methods on the test instance, etc. - -[[extensions-parameter-resolution]] -=== Parameter Resolution - -`{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at -runtime. - -If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at -runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. -Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any -combination thereof. - -If you wish to implement a custom `{ParameterResolver}` that resolves parameters based -solely on the type of the parameter, you may find it convenient to extend the -`{TypeBasedParameterResolver}` which serves as a generic adapter for such use cases. - -For concrete examples, consult the source code for `{CustomTypeParameterResolver}`, -`{CustomAnnotationParameterResolver}`, and `{MapOfListsTypeBasedParameterResolver}`. - -[WARNING] -==== -Due to a bug in the byte code generated by `javac` on JDK versions prior to JDK 9, -looking up annotations on parameters directly via the core `java.lang.reflect.Parameter` -API will always fail for _inner class_ constructors (e.g., a constructor in a `@Nested` -test class). - -The `{ParameterContext}` API supplied to `ParameterResolver` implementations therefore -includes the following convenience methods for correctly looking up annotations on -parameters. Extension authors are strongly encouraged to use these methods instead of -those provided in `java.lang.reflect.Parameter` in order to avoid this bug in the JDK. - -* `boolean isAnnotated(Class annotationType)` -* `Optional findAnnotation(Class annotationType)` -* `List findRepeatableAnnotations(Class annotationType)` -==== - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to support injecting test specific data into constructor parameters of the -test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while -resolving constructor parameters, unless the -<> is set to `PER_CLASS`. -==== - -[TIP] -.Parameter resolution for methods called from extensions -==== -Other extensions can also leverage registered `ParameterResolvers` for method and -constructor invocations, using the `{ExecutableInvoker}` available via the -`getExecutableInvoker()` method in the `ExtensionContext`. -==== - -[[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts - -If multiple implementations of `ParameterResolver` that support the same type are -registered for a test, a `ParameterResolutionException` will be thrown, with a -message to indicate that competing resolvers have been discovered. See the following -example: - -[source,java,indent=0] -.Conflicting parameter resolution due to multiple resolvers claiming support for integers ----- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations are applied to different test -methods as shown in the following example, no conflict occurs. - -[source,java,indent=0] -.Fine-grained registration to avoid conflict ----- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ----- - -If the conflicting `ParameterResolver` implementations need to be applied to the same test -method, you can implement a custom type or custom annotation as illustrated by -`{CustomTypeParameterResolver}` and `{CustomAnnotationParameterResolver}`, respectively. - -[source,java,indent=0] -.Custom type to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ----- - -A custom annotation makes the duplicate type distinguishable from its counterpart: - -[source,java,indent=0] -.Custom annotation to resolve duplicate types ----- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ----- - -JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver -attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such -as Spring may also define parameter resolvers. Apply one of the techniques in this section -to resolve any conflicts. - -Parameterized tests are another potential source of conflict. Ensure that tests annotated -with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. - [[extensions-test-result-processing]] === Test Result Processing @@ -628,630 +51,3 @@ invoked (see <>). You can use the parent context's `St work with such resources. ==== -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks - -The following interfaces define the APIs for extending tests at various points in the -test execution lifecycle. Consult the following sections for examples and the Javadoc for -each of these interfaces in the `{extension-api-package}` package for further details. - -* `{BeforeAllCallback}` -** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) -*** `{BeforeEachCallback}` -**** `{BeforeTestExecutionCallback}` -**** `{AfterTestExecutionCallback}` -*** `{AfterEachCallback}` -** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) -* `{AfterAllCallback}` - -.Implementing Multiple Extension APIs -NOTE: Extension developers may choose to implement any number of these interfaces -within a single extension. Consult the source code of the `{SpringExtension}` for a -concrete example. - -[[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks - -`{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for -`Extensions` that wish to add behavior that will be executed _immediately before_ and -_immediately after_ a test method is executed, respectively. As such, these callbacks are -well suited for timing, tracing, and similar use cases. If you need to implement -callbacks that are invoked _around_ `@BeforeEach` and `@AfterEach` methods, implement -`BeforeEachCallback` and `AfterEachCallback` instead. - -The following example shows how to use these callbacks to calculate and log the execution -time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` -and `AfterTestExecutionCallback` in order to time and log the test execution. - -[[extensions-lifecycle-callbacks-timing-extension]] -[source,java,indent=0] -.An extension that times and logs the execution of test methods ----- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] ----- - -Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, -its tests will have this timing applied when they execute. - -[source,java,indent=0] -.A test class that uses the example TimingExtension ----- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] ----- - -The following is an example of the logging produced when `TimingExtensionTests` is run. - -.... -INFO: Method [sleep20ms] took 24 ms. -INFO: Method [sleep50ms] took 53 ms. -.... - -[[extensions-exception-handling]] -=== Exception Handling - -Exceptions thrown during the test execution may be intercepted and handled accordingly -before propagating further, so that certain actions like error logging or resource releasing -may be defined in specialized `Extensions`. JUnit Jupiter offers API for `Extensions` that -wish to handle exceptions thrown during `@Test` methods via `{TestExecutionExceptionHandler}` -and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@BeforeEach`, -`@AfterEach` and `@AfterAll`) via `{LifecycleMethodExecutionExceptionHandler}`. - -The following example shows an extension which will swallow all instances of `IOException` -but rethrow any other type of exception. - -[source,java,indent=0] -.An exception handling extension that filters IOExceptions in test execution ----- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ----- - -Another example shows how to record the state of an application under test exactly at -the point of unexpected exception being thrown during setup and cleanup. Note that unlike -relying on lifecycle callbacks, which may or may not be executed depending on the test -status, this solution guarantees execution immediately after failing `@BeforeAll`, -`@BeforeEach`, `@AfterEach` or `@AfterAll`. - -[source,java,indent=0] -.An exception handling extension that records application state on error ----- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ----- - -Multiple execution exception handlers may be invoked for the same lifecycle method in -order of declaration. If one of the handlers swallows the handled exception, subsequent -ones will not be executed, and no failure will be propagated to JUnit engine, as if the -exception was never thrown. Handlers may also choose to rethrow the exception or throw -a different one, potentially wrapping the original. - -Extensions implementing `{LifecycleMethodExecutionExceptionHandler}` that wish to handle -exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a class level, -while handlers for `BeforeEach` and `AfterEach` may be also registered for individual -test methods. - -[source,java,indent=0] -.Registering multiple exception handling extensions ----- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ----- - -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback - -`{PreInterruptCallback}` defines the API for `Extensions` that wish to react on -timeouts before the `Thread.interrupt()` is called. - -Please refer to <> for additional information. - - -[[extensions-intercepting-invocations]] -=== Intercepting Invocations - -`{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to -test code. - -The following example shows an extension that executes all test methods in Swing's Event -Dispatch Thread. - -[source,java,indent=0] -.An extension that executes tests in a user-defined thread ----- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ----- - -[NOTE] -.Accessing the test-scoped `ExtensionContext` -==== -You may override the `getTestInstantiationExtensionContextScope(...)` method to return -`TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> -on the test method level. -==== - -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates - -A `{ClassTemplate}` class can only be executed when at least one -`{ClassTemplateInvocationContextProvider}` is registered. Each such provider is -responsible for providing a `Stream` of `{ClassTemplateInvocationContext}` instances. -Each context may specify a custom display name and a list of additional extensions that -will only be used for the next invocation of the `{ClassTemplate}`. - -The following example shows how to write a class template as well as how to register -and implement a `{ClassTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A class template with accompanying extension ----- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] ----- - -In this example, the class template will be invoked twice, meaning all test methods in -the class template will be executed twice. The display names of the invocations will be -`apple` and `banana` as specified by the invocation context. Each invocation registers a -custom `{TestInstancePostProcessor}` which is used to inject a value into a field. The -output when using the `ConsoleLauncher` is as follows. - -.... -└─ ClassTemplateDemo ✔ - ├─ apple ✔ - │ ├─ notNull() ✔ - │ └─ wellKnown() ✔ - └─ banana ✔ - ├─ notNull() ✔ - └─ wellKnown() ✔ -.... - -The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of _all_ test -methods in a test class albeit in different contexts — for example, with different -parameters, by preparing the test class instance differently, or multiple times without -modifying the context. -Please refer to the implementations of -<> which uses this extension -point to provide its functionality. - -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates - -A `{TestTemplate}` method can only be executed when at least one -`{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible -for providing a `Stream` of `{TestTemplateInvocationContext}` instances. Each context may -specify a custom display name and a list of additional extensions that will only be used -for the next invocation of the `{TestTemplate}` method. - -The following example shows how to write a test template as well as how to register and -implement a `{TestTemplateInvocationContextProvider}`. - -[source,java,indent=0] -.A test template with accompanying extension ----- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] ----- - -In this example, the test template will be invoked twice. The display names of the -invocations will be `apple` and `banana` as specified by the invocation context. Each -invocation registers a custom `{ParameterResolver}` which is used to resolve the method -parameter. The output when using the `ConsoleLauncher` is as follows. - -.... -└─ testTemplate(String) ✔ - ├─ apple ✔ - └─ banana ✔ -.... - -The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for -implementing different kinds of tests that rely on repetitive invocation of a test-like -method albeit in different contexts — for example, with different parameters, by preparing -the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point -to provide their functionality. - -[[extensions-keeping-state]] -=== Keeping State in Extensions - -Usually, an extension is instantiated only once. So the question becomes relevant: How do -you keep the state from one invocation of an extension to the next? The -`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. -Extensions may put values into a store for later retrieval. - -TIP: See the `<>` for an -example of using the `Store` with a method-level scope. - -.The `ExtensionContext` and `Store` hierarchy -image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center] - -As illustrated by the diagram above, stores are hierarchical in nature. When looking up a -value, if no value is stored in the current `ExtensionContext` for the supplied key, the -stores of the context's ancestors will be queried for a value with the same key in the -`Namespace` used to create this store. The root `ExtensionContext` represents the engine -level so its `Store` may be used to store or cache values that are used by multiple test -classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even -that and access the stores on the level of the current `{LauncherExecutionRequest}` or -`{LauncherSession}` which can be used to share data across test engines or inject data -from a registered -<>, -respectively. Please consult the Javadoc of `{ExtensionContext}`, -`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. - -[[extensions-keeping-state-autocloseable-support]] -[NOTE] -.Resource management via `_AutoCloseable_` -==== -An extension context store is bound to its extension context lifecycle. When an extension -context lifecycle ends it closes its associated store. - -All stored values that are instances of `AutoCloseable` are notified by an invocation of -their `close()` method in the inverse order they were added in (unless the -`junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). - -Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still -available for backward compatibility. -==== - -An example implementation of `AutoCloseable` is shown below, using an `HttpServer` -resource. - -[source,java,indent=0] -.`_HttpServer_` resource implementing `_AutoCloseable_` ----- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] ----- - -This resource can then be stored in the desired `ExtensionContext`. It may be stored at -class or method level, if desired, but this may add unnecessary overhead for this type of -resource. For this example it might be prudent to store it at root level and instantiate -it lazily to ensure it's only created once per test run and reused across different test -classes and methods. - -[source,java,indent=0] -.Lazily storing in root context with `_Store.computeIfAbsent_` ----- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] ----- - -[source,java,indent=0] -.A test case using the `_HttpServerExtension_` ----- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] ----- - -[[extensions-keeping-state-autocloseable-migration]] -[TIP] -.Migration Note for Resource Cleanup -==== -The framework automatically closes resources stored in the `ExtensionContext.Store` that -implement `AutoCloseable`. In versions prior to 5.13, only resources implementing -`Store.CloseableResource` were automatically closed. - -If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and -earlier versions and your extension stores resources that need to be cleaned up, you -should implement both interfaces: - -[source,java,indent=0] ----- -public class MyResource implements Store.CloseableResource, AutoCloseable { - @Override - public void close() throws Exception { - // Resource cleanup code - } -} ----- - -This ensures that your resource will be properly closed regardless of which JUnit Jupiter -version is being used. -==== - -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions - -The `junit-platform-commons` artifact provides _maintained_ utilities for working with -annotations, classes, reflection, classpath scanning, and conversion tasks. These -utilities can be found in the `{junit-platform-support-package}` and its subpackages. -`TestEngine` and `Extension` authors are encouraged to use these supported utilities in -order to align with the behavior of the JUnit Platform and JUnit Jupiter. - -[[extensions-supported-utilities-annotations]] -==== Annotation Support - -`AnnotationSupport` provides static utility methods that operate on annotated elements -(e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). -These include methods to check whether an element is annotated or meta-annotated with a -particular annotation, to search for specific annotations, and to find annotated methods -and fields in a class or interface. Some of these methods search on implemented -interfaces and within class hierarchies to find annotations. Consult the Javadoc for -`{AnnotationSupport}` for further details. - -NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, -use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. - -NOTE: See also: <> - -[[extensions-supported-utilities-classes]] -==== Class Support - -`ClassSupport` provides static utility methods for working with classes (i.e., instances -of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. - -[[extensions-supported-utilities-reflection]] -==== Reflection Support - -`ReflectionSupport` provides static utility methods that augment the standard JDK -reflection and class-loading mechanisms. These include methods to scan the classpath in -search of classes matching specified predicates, to load and create new instances of a -class, and to find and invoke methods. Some of these methods traverse class hierarchies -to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further -details. - -NOTE: See also: <> - -[[extensions-supported-utilities-modifier]] -==== Modifier Support - -`ModifierSupport` provides static utility methods for working with member and class -modifiers -- for example, to determine if a member is declared as `public`, `private`, -`abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further -details. - -[[extensions-supported-utilities-conversion]] -==== Conversion Support - -`ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) -provides support for converting from strings to primitive types and their corresponding -wrapper types, date and time types from the `java.time package`, and some additional -common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, -`URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. - -[[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics - -Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that -traverse type hierarchies to locate matching fields and methods – for example, -`AnnotationSupport.findAnnotatedFields(...)`, `ReflectionSupport.findMethods(...)`, etc. - -The field and method search algorithms adhere to standard Java semantics regarding whether -a given field or method is visible or overridden according to the rules of the Java -language. - -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions - -When executing a test class that contains one or more test methods, a number of extension -callbacks are called in addition to the user-supplied test and lifecycle methods. - -NOTE: See also: <> - -[[extensions-execution-order-overview]] -==== User and Extension Code - -The following diagram illustrates the relative order of user-supplied code and extension -code. User-supplied test and lifecycle methods are shown in orange, with callback code -implemented by extensions shown in blue. The grey box denotes the execution of a single -test method and will be repeated for every test method in the test class. - -[[extensions-execution-order-diagram]] -.User code and extension code -image::extensions_lifecycle.png[] - -The following table further explains the sixteen steps in the -<> diagram. - -. *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + -extension code executed before all tests of the container are executed -. *annotation* `*org.junit.jupiter.api.BeforeAll*` + -user code executed before all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeAll` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + -extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) -. *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + -extension code executed before each test is executed -. *annotation* `*org.junit.jupiter.api.BeforeEach*` + -user code executed before each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleBeforeEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@BeforeEach` methods -. *interface* `*org.junit.jupiter.api.extension.BeforeTestExecutionCallback*` + -extension code executed immediately before a test is executed -. *annotation* `*org.junit.jupiter.api.Test*` + -user code of the actual test method -. *interface* `*org.junit.jupiter.api.extension.TestExecutionExceptionHandler*` + -extension code for handling exceptions thrown during a test -. *interface* `*org.junit.jupiter.api.extension.AfterTestExecutionCallback*` + -extension code executed immediately after test execution and its corresponding exception handlers -. *annotation* `*org.junit.jupiter.api.AfterEach*` + -user code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterEachMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterEach` methods -. *interface* `*org.junit.jupiter.api.extension.AfterEachCallback*` + -extension code executed after each test is executed -. *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + -extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) -. *annotation* `*org.junit.jupiter.api.AfterAll*` + -user code executed after all tests of the container are executed -. *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler -#handleAfterAllMethodExecutionException*` + -extension code for handling exceptions thrown from `@AfterAll` methods -. *interface* `*org.junit.jupiter.api.extension.AfterAllCallback*` + -extension code executed after all tests of the container are executed - -In the simplest case only the actual test method will be executed (step 9); all other -steps are optional depending on the presence of user code or extension support for the -corresponding lifecycle callback. For further details on the various lifecycle callbacks -please consult the respective Javadoc for each annotation and extension. - -All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. - -[[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks - -JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions -that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, -`BeforeClassTemplateInvocationCallback`, `AfterClassTemplateInvocationCallback`, -`BeforeEachCallback`, `AfterEachCallback`, `BeforeTestExecutionCallback`, and -`AfterTestExecutionCallback`. - -That means that, given two extensions `Extension1` and `Extension2` with `Extension1` -registered before `Extension2`, any "before" callbacks implemented by `Extension1` are -guaranteed to execute **before** any "before" callbacks implemented by `Extension2`. -Similarly, given the two same two extensions registered in the same order, any "after" -callbacks implemented by `Extension1` are guaranteed to execute **after** any "after" -callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ -`Extension2`. - -JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). - -* `@BeforeAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed - **before** `@BeforeAll` methods in subclasses. -** Similarly, `@BeforeAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@BeforeAll` methods from an interface will be executed - **before** `@BeforeAll` methods in the class that implements the interface. -* `@AfterAll` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterAll` methods from superclasses will be executed - **after** `@AfterAll` methods in subclasses. -** Similarly, `@AfterAll` methods declared in an interface are inherited as long as they - are not _overridden_, and `@AfterAll` methods from an interface will be executed - **after** `@AfterAll` methods in the class that implements the interface. -* `@BeforeEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@BeforeEach` methods from superclasses will be executed - **before** `@BeforeEach` methods in subclasses. -** Similarly, `@BeforeEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@BeforeEach` default methods will be executed - **before** `@BeforeEach` methods in the class that implements the interface. -* `@AfterEach` methods are inherited from superclasses as long as they are not - _overridden_. Furthermore, `@AfterEach` methods from superclasses will be executed - **after** `@AfterEach` methods in subclasses. -** Similarly, `@AfterEach` methods declared as interface default methods are inherited as - long as they are not _overridden_, and `@AfterEach` default methods will be executed - **after** `@AfterEach` methods in the class that implements the interface. - -The following examples demonstrate this behavior. Please note that the examples do not -actually do anything realistic. Instead, they mimic common scenarios for testing -interactions with the database. All methods imported statically from the `Logger` class -log contextual information in order to help us better understand the execution order of -user-supplied callback methods and callback methods in extensions. - -[source,java,indent=0] -.Extension1 ----- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] ----- - -[source,java,indent=0] -.Extension2 ----- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] ----- - -[source,java,indent=0] -.AbstractDatabaseTests ----- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ----- - -[source,java,indent=0] -.DatabaseTestsDemo ----- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ----- - -When the `DatabaseTestsDemo` test class is executed, the following is logged. - ----- -@BeforeAll AbstractDatabaseTests.createDatabase() -@BeforeAll DatabaseTestsDemo.beforeAll() - Extension1.beforeEach() - Extension2.beforeEach() - @BeforeEach AbstractDatabaseTests.connectToDatabase() - @BeforeEach DatabaseTestsDemo.insertTestDataIntoDatabase() - @Test DatabaseTestsDemo.testDatabaseFunctionality() - @AfterEach DatabaseTestsDemo.deleteTestDataFromDatabase() - @AfterEach AbstractDatabaseTests.disconnectFromDatabase() - Extension2.afterEach() - Extension1.afterEach() -@BeforeAll DatabaseTestsDemo.afterAll() -@AfterAll AbstractDatabaseTests.destroyDatabase() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `DatabaseTestsDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_DatabaseTestsDemo.png[caption='',title='DatabaseTestsDemo'] - -JUnit Jupiter does **not** guarantee the execution order of multiple lifecycle methods -that are declared within a _single_ test class or test interface. It may at times appear -that JUnit Jupiter invokes such methods in alphabetical order. However, that is not -precisely true. The ordering is analogous to the ordering for `@Test` methods within a -single test class. - -[NOTE] -==== -Lifecycle methods that are declared within a _single_ test class or test interface will be -ordered using an algorithm that is deterministic but intentionally non-obvious. This -ensures that subsequent runs of a test suite execute lifecycle methods in the same order, -thereby allowing for repeatable builds. -==== - -In addition, JUnit Jupiter does **not** support _wrapping_ behavior for multiple lifecycle -methods declared within a single test class or test interface. - -The following example demonstrates this behavior. Specifically, the lifecycle method -configuration is _broken_ due to the order in which the locally declared lifecycle methods -are executed. - -* Test data is inserted _before_ the database connection has been opened, which results in - a failure to connect to the database. -* The database connection is closed _before_ deleting the test data, which results in a - failure to connect to the database. - -[source,java,indent=0] -.BrokenLifecycleMethodConfigDemo ----- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ----- - -When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. - ----- -Extension1.beforeEach() -Extension2.beforeEach() - @BeforeEach BrokenLifecycleMethodConfigDemo.insertTestDataIntoDatabase() - @BeforeEach BrokenLifecycleMethodConfigDemo.connectToDatabase() - @Test BrokenLifecycleMethodConfigDemo.testDatabaseFunctionality() - @AfterEach BrokenLifecycleMethodConfigDemo.disconnectFromDatabase() - @AfterEach BrokenLifecycleMethodConfigDemo.deleteTestDataFromDatabase() -Extension2.afterEach() -Extension1.afterEach() ----- - -The following sequence diagram helps to shed further light on what actually goes on within -the `JupiterTestEngine` when the `BrokenLifecycleMethodConfigDemo` test class is executed. - -//// -PNG generated using ZenUML: https://app.zenuml.com - -See corresponding *.txt file in images folder for the source. -//// -image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLifecycleMethodConfigDemo'] - -[TIP] -==== -Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test -class or test interface unless there are no dependencies between such lifecycle methods. -==== From d9b8c5468ca39c6c26b92a1d84e9ea60d203cb14 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:13 +0100 Subject: [PATCH 29/57] Migrate extensions sections to Antora syntax --- .../conditional-test-execution.adoc | 8 ++--- .../pages/extensions/exception-handling.adoc | 10 +++--- .../extensions/intercepting-invocations.adoc | 6 ++-- .../keeping-state-in-extensions.adoc | 10 +++--- .../ROOT/pages/extensions/overview.adoc | 4 +-- .../extensions/parameter-resolution.adoc | 14 ++++---- .../extensions/pre-interrupt-callback.adoc | 5 +-- ...vocation-contexts-for-class-templates.adoc | 6 ++-- ...nvocation-contexts-for-test-templates.adoc | 6 ++-- .../extensions/registering-extensions.adoc | 34 +++++++++---------- ...ion-order-of-user-code-and-extensions.adoc | 17 +++++----- .../supported-utilities-in-extensions.adoc | 16 ++++----- .../extensions/test-instance-factories.adoc | 4 +-- .../test-instance-post-processing.adoc | 4 +-- .../test-instance-pre-construct-callback.adoc | 4 +-- .../test-instance-pre-destroy-callback.adoc | 4 +-- .../extensions/test-lifecycle-callbacks.adoc | 10 +++--- .../extensions/test-result-processing.adoc | 4 +-- 18 files changed, 65 insertions(+), 101 deletions(-) diff --git a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc index 5dfa63cccd3c..8efca7980733 100644 --- a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc @@ -1,5 +1,4 @@ -[[extensions-conditions]] -=== Conditional Test Execution += Conditional Test Execution `{ExecutionCondition}` defines the `Extension` API for programmatic, _conditional test execution_. @@ -19,7 +18,7 @@ short-circuiting boolean OR operator. See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. [[extensions-conditions-deactivation]] -==== Deactivating Conditions +== Deactivating Conditions Sometimes it can be useful to run a test suite _without_ certain conditions being active. For example, you may wish to run tests even if they are annotated with `@Disabled` in @@ -36,7 +35,6 @@ following system property. `-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` [[extensions-conditions-deactivation-patterns]] -===== Pattern Matching Syntax +=== Pattern Matching Syntax Refer to <> for details. - diff --git a/documentation/modules/ROOT/pages/extensions/exception-handling.adoc b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc index a6629a46d72b..b4eb6d0eb213 100644 --- a/documentation/modules/ROOT/pages/extensions/exception-handling.adoc +++ b/documentation/modules/ROOT/pages/extensions/exception-handling.adoc @@ -1,5 +1,4 @@ -[[extensions-exception-handling]] -=== Exception Handling += Exception Handling Exceptions thrown during the test execution may be intercepted and handled accordingly before propagating further, so that certain actions like error logging or resource releasing @@ -14,7 +13,7 @@ but rethrow any other type of exception. [source,java,indent=0] .An exception handling extension that filters IOExceptions in test execution ---- -include::{testDir}/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] +include::example$java/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide] ---- Another example shows how to record the state of an application under test exactly at @@ -26,7 +25,7 @@ status, this solution guarantees execution immediately after failing `@BeforeAll [source,java,indent=0] .An exception handling extension that records application state on error ---- -include::{testDir}/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] +include::example$java/example/exception/RecordStateOnErrorExtension.java[tags=user_guide] ---- Multiple execution exception handlers may be invoked for the same lifecycle method in @@ -43,6 +42,5 @@ test methods. [source,java,indent=0] .Registering multiple exception handling extensions ---- -include::{testDir}/example/exception/MultipleHandlersTestCase.java[tags=user_guide] +include::example$java/example/exception/MultipleHandlersTestCase.java[tags=user_guide] ---- - diff --git a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc index 590543f1a86d..c78e1edc00e5 100644 --- a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc +++ b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc @@ -1,5 +1,4 @@ -[[extensions-intercepting-invocations]] -=== Intercepting Invocations += Intercepting Invocations `{InvocationInterceptor}` defines the API for `Extensions` that wish to intercept calls to test code. @@ -10,7 +9,7 @@ Dispatch Thread. [source,java,indent=0] .An extension that executes tests in a user-defined thread ---- -include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] +include::example$java/example/interceptor/SwingEdtInterceptor.java[tags=user_guide] ---- [NOTE] @@ -21,4 +20,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to `interceptTestClassConstructor` or if you want to <> on the test method level. ==== - diff --git a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc index 51cc8a553c92..5017884c73f5 100644 --- a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc @@ -1,5 +1,4 @@ -[[extensions-keeping-state]] -=== Keeping State in Extensions += Keeping State in Extensions Usually, an extension is instantiated only once. So the question becomes relevant: How do you keep the state from one invocation of an extension to the next? The @@ -47,7 +46,7 @@ resource. [source,java,indent=0] .`_HttpServer_` resource implementing `_AutoCloseable_` ---- -include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide] +include::example$java/example/extensions/HttpServerResource.java[tags=user_guide] ---- This resource can then be stored in the desired `ExtensionContext`. It may be stored at @@ -59,13 +58,13 @@ classes and methods. [source,java,indent=0] .Lazily storing in root context with `_Store.computeIfAbsent_` ---- -include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide] +include::example$java/example/extensions/HttpServerExtension.java[tags=user_guide] ---- [source,java,indent=0] .A test case using the `_HttpServerExtension_` ---- -include::{testDir}/example/HttpServerDemo.java[tags=user_guide] +include::example$java/example/HttpServerDemo.java[tags=user_guide] ---- [[extensions-keeping-state-autocloseable-migration]] @@ -93,4 +92,3 @@ public class MyResource implements Store.CloseableResource, AutoCloseable { This ensures that your resource will be properly closed regardless of which JUnit Jupiter version is being used. ==== - diff --git a/documentation/modules/ROOT/pages/extensions/overview.adoc b/documentation/modules/ROOT/pages/extensions/overview.adoc index 8d2f8e4112b5..9bf16307643a 100644 --- a/documentation/modules/ROOT/pages/extensions/overview.adoc +++ b/documentation/modules/ROOT/pages/extensions/overview.adoc @@ -1,7 +1,5 @@ -[[extensions-overview]] -=== Overview += Extension Model In contrast to the competing `Runner`, `TestRule`, and `MethodRule` extension points in JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the `Extension` API. Note, however, that `Extension` itself is just a marker interface. - diff --git a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc index 6e92e3ab863d..c626f20c8530 100644 --- a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc +++ b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc @@ -1,5 +1,4 @@ -[[extensions-parameter-resolution]] -=== Parameter Resolution += Parameter Resolution `{ParameterResolver}` defines the `Extension` API for dynamically resolving parameters at runtime. @@ -54,7 +53,7 @@ constructor invocations, using the `{ExecutableInvoker}` available via the ==== [[extensions-parameter-resolution-conflicts]] -==== Parameter Conflicts +== Parameter Conflicts If multiple implementations of `ParameterResolver` that support the same type are registered for a test, a `ParameterResolutionException` will be thrown, with a @@ -64,7 +63,7 @@ example: [source,java,indent=0] .Conflicting parameter resolution due to multiple resolvers claiming support for integers ---- -include::{testDir}/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] +include::example$java/example/extensions/ParameterResolverConflictDemo.java[tags=user_guide] ---- If the conflicting `ParameterResolver` implementations are applied to different test @@ -73,7 +72,7 @@ methods as shown in the following example, no conflict occurs. [source,java,indent=0] .Fine-grained registration to avoid conflict ---- -include::{testDir}/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] +include::example$java/example/extensions/ParameterResolverNoConflictDemo.java[tags=user_guide] ---- If the conflicting `ParameterResolver` implementations need to be applied to the same test @@ -83,7 +82,7 @@ method, you can implement a custom type or custom annotation as illustrated by [source,java,indent=0] .Custom type to resolve duplicate types ---- -include::{testDir}/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] +include::example$java/example/extensions/ParameterResolverCustomTypeDemo.java[tags=user_guide] ---- A custom annotation makes the duplicate type distinguishable from its counterpart: @@ -91,7 +90,7 @@ A custom annotation makes the duplicate type distinguishable from its counterpar [source,java,indent=0] .Custom annotation to resolve duplicate types ---- -include::{testDir}/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] +include::example$java/example/extensions/ParameterResolverCustomAnnotationDemo.java[tags=user_guide] ---- JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver @@ -103,4 +102,3 @@ to resolve any conflicts. Parameterized tests are another potential source of conflict. Ensure that tests annotated with `@ParameterizedTest` are not also annotated with `@Test` and see <> for more details. - diff --git a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc index 5d34a551de65..5e61a03abe74 100644 --- a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc @@ -1,9 +1,6 @@ -[[extensions-preinterrupt-callback]] -=== Pre-Interrupt Callback += Pre-Interrupt Callback `{PreInterruptCallback}` defines the API for `Extensions` that wish to react on timeouts before the `Thread.interrupt()` is called. Please refer to <> for additional information. - - diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc index 7b0ac9babcab..f111450665bc 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc @@ -1,5 +1,4 @@ -[[extensions-class-templates]] -=== Providing Invocation Contexts for Class Templates += Providing Invocation Contexts for Class Templates A `{ClassTemplate}` class can only be executed when at least one `{ClassTemplateInvocationContextProvider}` is registered. Each such provider is @@ -13,7 +12,7 @@ and implement a `{ClassTemplateInvocationContextProvider}`. [source,java,indent=0] .A class template with accompanying extension ---- -include::{testDir}/example/ClassTemplateDemo.java[tags=user_guide] +include::example$java/example/ClassTemplateDemo.java[tags=user_guide] ---- In this example, the class template will be invoked twice, meaning all test methods in @@ -40,4 +39,3 @@ modifying the context. Please refer to the implementations of <> which uses this extension point to provide its functionality. - diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc index 4a4d22c5ca6c..b7b488180b5b 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc @@ -1,5 +1,4 @@ -[[extensions-test-templates]] -=== Providing Invocation Contexts for Test Templates += Providing Invocation Contexts for Test Templates A `{TestTemplate}` method can only be executed when at least one `{TestTemplateInvocationContextProvider}` is registered. Each such provider is responsible @@ -13,7 +12,7 @@ implement a `{TestTemplateInvocationContextProvider}`. [source,java,indent=0] .A test template with accompanying extension ---- -include::{testDir}/example/TestTemplateDemo.java[tags=user_guide] +include::example$java/example/TestTemplateDemo.java[tags=user_guide] ---- In this example, the test template will be invoked twice. The display names of the @@ -34,4 +33,3 @@ the test class instance differently, or multiple times without modifying the con Please refer to the implementations of <> or <> which use this extension point to provide their functionality. - diff --git a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc index 3dd520298948..d7d9dedbf39b 100644 --- a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc @@ -1,5 +1,4 @@ -[[extensions-registration]] -=== Registering Extensions += Registering Extensions Extensions can be registered _declaratively_ via <>, _programmatically_ via @@ -7,7 +6,7 @@ Extensions can be registered _declaratively_ via Java's <> mechanism. [[extensions-registration-declarative]] -==== Declarative Extension Registration +== Declarative Extension Registration Developers can register one or more extensions _declaratively_ by annotating a test interface, test class, test method, or custom _<> and <> support @@ -277,7 +276,7 @@ name in a file named `org.junit.jupiter.api.extension.Extension` within the `/META-INF/services` folder in its enclosing JAR file. [[extensions-registration-automatic-enabling]] -===== Enabling Automatic Extension Detection +=== Enabling Automatic Extension Detection Auto-detection is an advanced feature and is therefore not enabled by default. To enable it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to @@ -295,7 +294,7 @@ will be added to the extension registry after JUnit Jupiter's global extensions support for `TestInfo`, `TestReporter`, etc.). [[extensions-registration-automatic-filtering]] -===== Filtering Auto-detected Extensions +=== Filtering Auto-detected Extensions The list of auto-detected extensions can be filtered using include and exclude patterns via the following <>: @@ -312,7 +311,7 @@ match any exclude pattern will be auto-detected. See <> for details on the pattern syntax. [[extensions-registration-inheritance]] -==== Extension Inheritance +== Extension Inheritance Registered extensions are inherited within test class hierarchies with top-down semantics. Similarly, extensions registered at the class-level are inherited at the method-level. @@ -331,4 +330,3 @@ Extension Registration Order>> for details). NOTE: A specific extension implementation can only be registered once for a given extension context and its parent contexts. Consequently, any attempt to register a duplicate extension implementation will be ignored. - diff --git a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc index 8e5da6d38612..f062f7987df0 100644 --- a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc @@ -1,5 +1,4 @@ -[[extensions-execution-order]] -=== Relative Execution Order of User Code and Extensions += Relative Execution Order of User Code and Extensions When executing a test class that contains one or more test methods, a number of extension callbacks are called in addition to the user-supplied test and lifecycle methods. @@ -7,7 +6,7 @@ callbacks are called in addition to the user-supplied test and lifecycle methods NOTE: See also: <> [[extensions-execution-order-overview]] -==== User and Extension Code +== User and Extension Code The following diagram illustrates the relative order of user-supplied code and extension code. User-supplied test and lifecycle methods are shown in orange, with callback code @@ -73,7 +72,7 @@ All invocations of user code methods in the above table can additionally be inte by implementing <>. [[extensions-execution-order-wrapping-behavior]] -==== Wrapping Behavior of Callbacks +== Wrapping Behavior of Callbacks JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions that implement lifecycle callbacks such as `BeforeAllCallback`, `AfterAllCallback`, @@ -126,25 +125,25 @@ user-supplied callback methods and callback methods in extensions. [source,java,indent=0] .Extension1 ---- -include::{testDir}/example/callbacks/Extension1.java[tags=user_guide] +include::example$java/example/callbacks/Extension1.java[tags=user_guide] ---- [source,java,indent=0] .Extension2 ---- -include::{testDir}/example/callbacks/Extension2.java[tags=user_guide] +include::example$java/example/callbacks/Extension2.java[tags=user_guide] ---- [source,java,indent=0] .AbstractDatabaseTests ---- -include::{testDir}/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] +include::example$java/example/callbacks/AbstractDatabaseTests.java[tags=user_guide] ---- [source,java,indent=0] .DatabaseTestsDemo ---- -include::{testDir}/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] +include::example$java/example/callbacks/DatabaseTestsDemo.java[tags=user_guide] ---- When the `DatabaseTestsDemo` test class is executed, the following is logged. @@ -204,7 +203,7 @@ are executed. [source,java,indent=0] .BrokenLifecycleMethodConfigDemo ---- -include::{testDir}/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] +include::example$java/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide] ---- When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged. diff --git a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc index 0bd27a99d5a2..38ca96625bab 100644 --- a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc @@ -1,5 +1,4 @@ -[[extensions-supported-utilities]] -=== Supported Utilities in Extensions += Supported Utilities in Extensions The `junit-platform-commons` artifact provides _maintained_ utilities for working with annotations, classes, reflection, classpath scanning, and conversion tasks. These @@ -8,7 +7,7 @@ utilities can be found in the `{junit-platform-support-package}` and its subpack order to align with the behavior of the JUnit Platform and JUnit Jupiter. [[extensions-supported-utilities-annotations]] -==== Annotation Support +== Annotation Support `AnnotationSupport` provides static utility methods that operate on annotated elements (e.g., packages, annotations, classes, interfaces, constructors, methods, and fields). @@ -24,13 +23,13 @@ use one of the `findRepeatableAnnotations()` methods and verify that the returne NOTE: See also: <> [[extensions-supported-utilities-classes]] -==== Class Support +== Class Support `ClassSupport` provides static utility methods for working with classes (i.e., instances of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. [[extensions-supported-utilities-reflection]] -==== Reflection Support +== Reflection Support `ReflectionSupport` provides static utility methods that augment the standard JDK reflection and class-loading mechanisms. These include methods to scan the classpath in @@ -42,7 +41,7 @@ details. NOTE: See also: <> [[extensions-supported-utilities-modifier]] -==== Modifier Support +== Modifier Support `ModifierSupport` provides static utility methods for working with member and class modifiers -- for example, to determine if a member is declared as `public`, `private`, @@ -50,7 +49,7 @@ modifiers -- for example, to determine if a member is declared as `public`, `pri details. [[extensions-supported-utilities-conversion]] -==== Conversion Support +== Conversion Support `ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) provides support for converting from strings to primitive types and their corresponding @@ -59,7 +58,7 @@ common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Local `URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. [[extensions-supported-utilities-search-semantics]] -==== Field and Method Search Semantics +== Field and Method Search Semantics Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that traverse type hierarchies to locate matching fields and methods – for example, @@ -68,4 +67,3 @@ traverse type hierarchies to locate matching fields and methods – for example, The field and method search algorithms adhere to standard Java semantics regarding whether a given field or method is visible or overridden according to the rules of the Java language. - diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc index ff042496c539..1682268d2ae5 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc @@ -1,5 +1,4 @@ -[[extensions-test-instance-factories]] -=== Test Instance Factories += Test Instance Factories `{TestInstanceFactory}` defines the API for `Extensions` that wish to _create_ test class instances. @@ -31,4 +30,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to `TEST_METHOD` to make test-specific data available to your extension implementation or if you want to <> on the test method level. ==== - diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc index 84dbc3bca5f3..41b8b3b3de28 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc @@ -1,5 +1,4 @@ -[[extensions-test-instance-post-processing]] -=== Test Instance Post-processing += Test Instance Post-processing `{TestInstancePostProcessor}` defines the API for `Extensions` that wish to _post process_ test instances. @@ -17,4 +16,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to `TEST_METHOD` to make test-specific data available to your extension implementation or if you want to <> on the test method level. ==== - diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc index 65a185ef79aa..4d4623367526 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc @@ -1,5 +1,4 @@ -[[extensions-test-instance-pre-construct-callback]] -=== Test Instance Pre-construct Callback += Test Instance Pre-construct Callback `{TestInstancePreConstructCallback}` defines the API for `Extensions` that wish to be invoked _prior_ to test instances being constructed (by a constructor call or via @@ -16,4 +15,3 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to `TEST_METHOD` to make test-specific data available to your extension implementation or if you want to <> on the test method level. ==== - diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc index acda444fb67a..4816c3a465c5 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-destroy-callback.adoc @@ -1,9 +1,7 @@ -[[extensions-test-instance-pre-destroy-callback]] -=== Test Instance Pre-destroy Callback += Test Instance Pre-destroy Callback `{TestInstancePreDestroyCallback}` defines the API for `Extensions` that wish to process test instances _after_ they have been used in tests and _before_ they are destroyed. Common use cases include cleaning dependencies that have been injected into the test instance, invoking custom de-initialization methods on the test instance, etc. - diff --git a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc index d34b10954a51..f0782ab64c31 100644 --- a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc @@ -1,5 +1,4 @@ -[[extensions-lifecycle-callbacks]] -=== Test Lifecycle Callbacks += Test Lifecycle Callbacks The following interfaces define the APIs for extending tests at various points in the test execution lifecycle. Consult the following sections for examples and the Javadoc for @@ -22,7 +21,7 @@ within a single extension. Consult the source code of the `{SpringExtension}` fo concrete example. [[extensions-lifecycle-callbacks-before-after-execution]] -==== Before and After Test Execution Callbacks +== Before and After Test Execution Callbacks `{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for `Extensions` that wish to add behavior that will be executed _immediately before_ and @@ -39,7 +38,7 @@ and `AfterTestExecutionCallback` in order to time and log the test execution. [source,java,indent=0] .An extension that times and logs the execution of test methods ---- -include::{testDir}/example/timing/TimingExtension.java[tags=user_guide] +include::example$java/example/timing/TimingExtension.java[tags=user_guide] ---- Since the `TimingExtensionTests` class registers the `TimingExtension` via `@ExtendWith`, @@ -48,7 +47,7 @@ its tests will have this timing applied when they execute. [source,java,indent=0] .A test class that uses the example TimingExtension ---- -include::{testDir}/example/timing/TimingExtensionTests.java[tags=user_guide] +include::example$java/example/timing/TimingExtensionTests.java[tags=user_guide] ---- The following is an example of the logging produced when `TimingExtensionTests` is run. @@ -57,4 +56,3 @@ The following is an example of the logging produced when `TimingExtensionTests` INFO: Method [sleep20ms] took 24 ms. INFO: Method [sleep50ms] took 53 ms. .... - diff --git a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc index 24e3ddf16680..c3d0f7503a1b 100644 --- a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc @@ -1,5 +1,4 @@ -[[extensions-test-result-processing]] -=== Test Result Processing += Test Result Processing `{TestWatcher}` defines the API for extensions that wish to process the results of _test method_ executions. Specifically, a `TestWatcher` will be invoked with contextual @@ -50,4 +49,3 @@ provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatche invoked (see <>). You can use the parent context's `Store` to work with such resources. ==== - From 336f793ef50b14df212fa18cd975396158857ad2 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:13 +0100 Subject: [PATCH 30/57] Add extensions sections to navigation --- documentation/modules/ROOT/nav.adoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 37c8b335fa42..4f6e26390b2b 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -36,3 +36,21 @@ ** xref:running-tests/using-listeners-and-interceptors.adoc[] ** xref:running-tests/stack-trace-pruning.adoc[] ** xref:running-tests/discovery-issues.adoc[] +* xref:extensions/overview.adoc[] +** xref:extensions/registering-extensions.adoc[] +** xref:extensions/conditional-test-execution.adoc[] +** xref:extensions/test-instance-pre-construct-callback.adoc[] +** xref:extensions/test-instance-factories.adoc[] +** xref:extensions/test-instance-post-processing.adoc[] +** xref:extensions/test-instance-pre-destroy-callback.adoc[] +** xref:extensions/parameter-resolution.adoc[] +** xref:extensions/test-result-processing.adoc[] +** xref:extensions/test-lifecycle-callbacks.adoc[] +** xref:extensions/exception-handling.adoc[] +** xref:extensions/pre-interrupt-callback.adoc[] +** xref:extensions/intercepting-invocations.adoc[] +** xref:extensions/providing-invocation-contexts-for-class-templates.adoc[] +** xref:extensions/providing-invocation-contexts-for-test-templates.adoc[] +** xref:extensions/keeping-state-in-extensions.adoc[] +** xref:extensions/supported-utilities-in-extensions.adoc[] +** xref:extensions/relative-execution-order-of-user-code-and-extensions.adoc[] From 2a204f8bfc7363de2c9f09e284c37a5e6ef2bec8 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:14 +0100 Subject: [PATCH 31/57] Remove Advanced Topics include file --- .../docs/asciidoc/user-guide/advanced-topics.adoc | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/user-guide/advanced-topics.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics.adoc b/documentation/src/docs/asciidoc/user-guide/advanced-topics.adoc deleted file mode 100644 index ab7f4d11463a..000000000000 --- a/documentation/src/docs/asciidoc/user-guide/advanced-topics.adoc +++ /dev/null @@ -1,12 +0,0 @@ -[[advanced-topics]] -== Advanced Topics - -include::advanced-topics/junit-platform-reporting.adoc[] - -include::advanced-topics/junit-platform-suite-engine.adoc[] - -include::advanced-topics/testkit.adoc[] - -include::advanced-topics/launcher-api.adoc[] - -include::advanced-topics/engines.adoc[] From 679dd6239d4057ff3fa888485100388e657dc3af Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:14 +0100 Subject: [PATCH 32/57] Move junit-platform-reporting.adoc to Antora module --- .../ROOT/pages}/advanced-topics/junit-platform-reporting.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/advanced-topics/junit-platform-reporting.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/junit-platform-reporting.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/advanced-topics/junit-platform-reporting.adoc rename to documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc From 94421b69ab4cc4c391f8864863e42fa0d26a2ee9 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:14 +0100 Subject: [PATCH 33/57] Migrate junit-platform-reporting.adoc to Antora syntax --- .../advanced-topics/junit-platform-reporting.adoc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc index 10f7744f54b0..2c4d89c4b85a 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc @@ -1,5 +1,4 @@ -[[junit-platform-reporting]] -=== JUnit Platform Reporting += JUnit Platform Reporting The `junit-platform-reporting` artifact contains `{TestExecutionListener}` implementations that generate XML test reports in two flavors: @@ -10,7 +9,7 @@ NOTE: The module also contains other `TestExecutionListener` implementations tha used to build custom reporting. See <> for details. [[junit-platform-reporting-output-directory]] -==== Output Directory +== Output Directory The JUnit Platform provides an `{OutputDirectoryCreator}` via `{EngineDiscoveryRequest}` and `{TestPlan}` to registered <> and @@ -29,7 +28,7 @@ Gradle's or Maven's parallel execution capabilities which create multiple JVM fo that run concurrently. [[junit-platform-reporting-open-test-reporting]] -==== Open Test Reporting +== Open Test Reporting `{OpenTestReportGeneratingListener}` writes an XML report for the entire execution in the event-based format specified by {OpenTestReporting} which supports all features of the @@ -58,7 +57,7 @@ written to `System.out` and `System.err` will be included in the report as well. TIP: The {OpenTestReportingCliTool} can be used to convert from the event-based format to the hierarchical format which is more human-readable. -===== Gradle +=== Gradle For Gradle, writing Open Test Reporting compatible XML reports can be enabled and configured via system properties. The following samples configure its output directory to @@ -102,7 +101,7 @@ tasks.withType().configureEach { } ---- -===== Maven +=== Maven For Maven Surefire/Failsafe, you can enable Open Test Reporting output and configure the resulting XML files to be written to the same directory Surefire/Failsafe uses for its own @@ -141,7 +140,7 @@ XML reports as follows: ---- -===== Console Launcher +=== Console Launcher When using the <>, you can enable Open Test Reporting output by setting the configuration parameters via `--config`: @@ -163,7 +162,7 @@ $ java -jar junit-platform-console-standalone-{version}.jar \ ---- [[junit-platform-reporting-legacy-xml]] -==== Legacy XML format +== Legacy XML format `{LegacyXmlReportGeneratingListener}` generates a separate XML report for each root in the `{TestPlan}`. Note that the generated XML format is compatible with the de facto standard From 1b25c9acb095e33cc05cf3e61872d2e43d7a6add Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:14 +0100 Subject: [PATCH 34/57] Move junit-platform-suite-engine.adoc to Antora module --- .../ROOT/pages}/advanced-topics/junit-platform-suite-engine.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/advanced-topics/junit-platform-suite-engine.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/junit-platform-suite-engine.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/advanced-topics/junit-platform-suite-engine.adoc rename to documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc From 1dc6ca42a0e28cadf9d80a6efe548fb623606f8f Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:15 +0100 Subject: [PATCH 35/57] Migrate junit-platform-suite-engine.adoc to Antora syntax --- .../junit-platform-suite-engine.adoc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc index 57c1f80dfa5f..5262d1332bee 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc @@ -1,5 +1,4 @@ -[[junit-platform-suite-engine]] -=== JUnit Platform Suite Engine += JUnit Platform Suite Engine The Suite Engine supports the declarative selection and execution of tests from _any_ test engine on the JUnit Platform using the <>. @@ -7,14 +6,14 @@ engine on the JUnit Platform using the <>. image::junit-platform-suite-engine-diagram.svg[role=text-center] [[junit-platform-suite-engine-setup]] -==== Setup +== Setup In addition to the `junit-platform-suite-api` and `junit-platform-suite-engine` artifacts, you need _at least one_ other test engine and its dependencies on the classpath. See <> for details regarding group IDs, artifact IDs, and versions. [[junit-platform-suite-engine-setup-required-dependencies]] -===== Required Dependencies +=== Required Dependencies * `junit-platform-suite-api` in _test_ scope: artifact containing annotations needed to configure a test suite @@ -26,7 +25,7 @@ artifact which can be declared in _test_ scope instead of declaring explicit dep on `junit-platform-suite-api` and `junit-platform-suite-engine`. [[junit-platform-suite-engine-setup-transitive-dependencies]] -===== Transitive Dependencies +=== Transitive Dependencies * `junit-platform-launcher` in _test_ scope * `junit-platform-engine` in _test_ scope @@ -34,7 +33,7 @@ on `junit-platform-suite-api` and `junit-platform-suite-engine`. * `opentest4j` in _test_ scope [[junit-platform-suite-engine-example]] -==== @Suite Example +== @Suite Example Annotate a class with `@Suite` to have it marked as a test suite on the JUnit Platform. As seen in the following example, selector and filter annotations can be used to control the @@ -42,7 +41,7 @@ contents of the suite. [source,java,indent=0] ---- -include::{testDir}/example/SuiteDemo.java[tags=user_guide] +include::example$java/example/SuiteDemo.java[tags=user_guide] ---- .Additional Configuration Options @@ -50,7 +49,7 @@ NOTE: There are numerous configuration options for discovering and filtering tes test suite. Please consult the Javadoc of the `{suite-api-package}` package for a full list of supported annotations and further details. -==== @BeforeSuite and @AfterSuite +== @BeforeSuite and @AfterSuite `@BeforeSuite` and `@AfterSuite` annotations can be used on methods inside a `@Suite`-annotated class. They will be executed before and after all tests of the test @@ -58,11 +57,11 @@ suite, respectively. [source,java,indent=0] ---- -include::{testDir}/example/BeforeAndAfterSuiteDemo.java[tags=user_guide] +include::example$java/example/BeforeAndAfterSuiteDemo.java[tags=user_guide] ---- [[junit-platform-suite-engine-duplicate-test-execution]] -==== Duplicate Test Execution +== Duplicate Test Execution Depending on the declared selectors, different suites may contain the same tests, potentially with different configurations. Moreover, tests in a suite are executed in From 1b09417560ed41cad8fdffb5bbd25295f451552c Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:15 +0100 Subject: [PATCH 36/57] Move testkit.adoc to Antora module --- .../ROOT/pages}/advanced-topics/testkit.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/advanced-topics/testkit.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/testkit.adoc b/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/advanced-topics/testkit.adoc rename to documentation/modules/ROOT/pages/advanced-topics/testkit.adoc From d81d53d442ef8cd544388292acc0d3bfd9a92ac8 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:15 +0100 Subject: [PATCH 37/57] Migrate testkit.adoc to Antora syntax --- .../ROOT/pages/advanced-topics/testkit.adoc | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc b/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc index b21678c3f38c..6910b8bea154 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc @@ -1,14 +1,11 @@ -:testDir: ../../../../../src/test/java - -[[testkit]] -=== JUnit Platform Test Kit += JUnit Platform Test Kit The `junit-platform-testkit` artifact provides support for executing a test plan on the JUnit Platform and then verifying the expected results. This support is currently limited to the execution of a single `TestEngine` (see <>). [[testkit-engine]] -==== Engine Test Kit +== Engine Test Kit The `{testkit-engine-package}` package provides support for discovering and executing a `{TestPlan}` for a given `{TestEngine}` running on the JUnit Platform and then accessing @@ -27,7 +24,7 @@ The following test class written using JUnit Jupiter will be used in subsequent [[testkit-engine-ExampleTestCase]] [source,java,indent=0] ---- -include::{testDir}/example/ExampleTestCase.java[tags=user_guide] +include::example$java/example/ExampleTestCase.java[tags=user_guide] ---- For the sake of brevity, the following sections demonstrate how to test JUnit's own @@ -37,14 +34,14 @@ may test your own `TestEngine` by supplying an instance of it to the `EngineTestKit.engine(TestEngine)` static factory method. [[testkit-engine-discovery]] -==== Verifying Test Discovery +== Verifying Test Discovery The following test demonstrates how to verify that a `TestPlan` was discovered as expected by the JUnit Jupiter `TestEngine`. [source,java,indent=0] ---- -include::{testDir}/example/testkit/EngineTestKitDiscoveryDemo.java[tags=user_guide] +include::example$java/example/testkit/EngineTestKitDiscoveryDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. <2> Select the <> test class. @@ -53,7 +50,7 @@ include::{testDir}/example/testkit/EngineTestKitDiscoveryDemo.java[tags=user_gui <5> Assert no discovery issues were encountered. [[testkit-engine-statistics]] -==== Asserting Execution Statistics +== Asserting Execution Statistics One of the most common features of the Test Kit is the ability to assert statistics against events fired during the execution of a `TestPlan`. The following tests demonstrate @@ -62,7 +59,7 @@ For details on what statistics are available, consult the Javadoc for `{EventSta [source,java,indent=0] ---- -include::{testDir}/example/testkit/EngineTestKitStatisticsDemo.java[tags=user_guide] +include::example$java/example/testkit/EngineTestKitStatisticsDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. <2> Select the <> test class. @@ -77,7 +74,7 @@ NOTE: In the `verifyJupiterContainerStats()` test method, the counts for the `st <> class are both considered containers. [[testkit-engine-events]] -==== Asserting Events +== Asserting Events If you find that <> alone is insufficient for verifying the expected behavior of test execution, you can work directly with the @@ -99,7 +96,7 @@ events, consult the Javadoc for `{EventConditions}`. [source,java,indent=0] ---- -include::{testDir}/example/testkit/EngineTestKitSkippedMethodDemo.java[tags=user_guide] +include::example$java/example/testkit/EngineTestKitSkippedMethodDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. <2> Select the `skippedTest()` method in the < Select the JUnit Jupiter `TestEngine`. <2> Select the <> test class. @@ -153,7 +150,7 @@ respectively. [source,java,indent=0] ---- -include::{testDir}/example/testkit/EngineTestKitAllEventsDemo.java[tags=user_guide] +include::example$java/example/testkit/EngineTestKitAllEventsDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. <2> Select the <> test class. From 16814761d8c79ff8daab325c14017ae7e381e1fb Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:16 +0100 Subject: [PATCH 38/57] Move launcher-api.adoc to Antora module --- .../ROOT/pages}/advanced-topics/launcher-api.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/advanced-topics/launcher-api.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/launcher-api.adoc b/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/advanced-topics/launcher-api.adoc rename to documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc From a19f51d1c862d7385176d96c9dd372fe115e0b35 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:16 +0100 Subject: [PATCH 39/57] Migrate launcher-api.adoc to Antora syntax --- .../pages/advanced-topics/launcher-api.adoc | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc b/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc index 434761485d2a..ac57b65a254c 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc @@ -1,8 +1,4 @@ -:testDir: ../../../../../src/test/java -:testResourcesDir: ../../../../../src/test/resources - -[[launcher-api]] -=== JUnit Platform Launcher API += JUnit Platform Launcher API One of the prominent goals of the JUnit Platform is to make the interface between JUnit and its programmatic clients – build tools and IDEs – more powerful and stable. The @@ -22,7 +18,7 @@ An example consumer of the launcher API is the `{ConsoleLauncher}` in the `{junit-platform-console}` project. [[launcher-api-discovery]] -==== Discovering Tests +== Discovering Tests Having _test discovery_ as a dedicated feature of the platform frees IDEs and build tools from most of the difficulties they had to go through to identify test classes and test @@ -32,12 +28,12 @@ Usage Example: [source,java,indent=0] ---- -include::{testDir}/example/UsingTheLauncherForDiscoveryDemo.java[tags=imports] +include::example$java/example/UsingTheLauncherForDiscoveryDemo.java[tags=imports] ---- [source,java,indent=0] ---- -include::{testDir}/example/UsingTheLauncherForDiscoveryDemo.java[tags=discovery] +include::example$java/example/UsingTheLauncherForDiscoveryDemo.java[tags=discovery] ---- You can select classes, methods, and all classes in a package or even search for all tests @@ -59,7 +55,7 @@ test discovery after the first discovery failure is encountered. The default parameter>>. [[launcher-api-execution]] -==== Executing Tests +== Executing Tests To execute tests, clients can use the same `LauncherDiscoveryRequest` as in the discovery phase or create a new request. Test progress and reporting can be achieved by registering @@ -68,7 +64,7 @@ following example. [source,java,indent=0] ---- -include::{testDir}/example/UsingTheLauncherDemo.java[tags=execution] +include::example$java/example/UsingTheLauncherDemo.java[tags=execution] ---- There is no return value for the `execute()` method, but you can use a @@ -82,13 +78,13 @@ reverse order. Test case execution won't start before all `executionStarted` calls have returned. [[launcher-api-engines-custom]] -==== Registering a TestEngine +== Registering a TestEngine See the dedicated section on <> for details. [[launcher-api-post-discovery-filters-custom]] -==== Registering a PostDiscoveryFilter +== Registering a PostDiscoveryFilter In addition to specifying post-discovery filters as part of a `{LauncherDiscoveryRequest}` passed to the `{Launcher}` API, `{PostDiscoveryFilter}` implementations will be discovered @@ -100,7 +96,7 @@ declared within the `/META-INF/services/org.junit.platform.launcher.PostDiscover file is loaded and applied automatically. [[launcher-api-launcher-session-listeners-custom]] -==== Registering a LauncherSessionListener +== Registering a LauncherSessionListener Registered implementations of `{LauncherSessionListener}` are notified when a `{LauncherSession}` is opened (before a `{Launcher}` first discovers and executes tests) @@ -110,7 +106,7 @@ they can be discovered at runtime via Java's `{ServiceLoader}` mechanism and aut registered with `LauncherSession` (unless automatic registration is disabled.) [[launcher-api-launcher-session-listeners-tool-support]] -===== Tool Support +=== Tool Support The following build tools and IDEs are known to provide full support for `LauncherSession`: @@ -121,7 +117,7 @@ The following build tools and IDEs are known to provide full support for `Launch Other tools might also work but have not been tested explicitly. [[launcher-api-launcher-session-listeners-tool-example-usage]] -===== Example Usage +=== Example Usage A `LauncherSessionListener` is well suited for implementing once-per-JVM setup/teardown behavior since it's called before the first and after the last test in a launcher session, @@ -135,7 +131,7 @@ executed, could look like this: ---- package example.session; -include::{testDir}/example/session/GlobalSetupTeardownListener.java[tags=user_guide] +include::example$java/example/session/GlobalSetupTeardownListener.java[tags=user_guide] ---- <1> Get the store from the launcher session <2> Lazily create the HTTP server and put it into the store @@ -149,7 +145,7 @@ closed: ---- package example.session; -include::{testDir}/example/session/CloseableHttpServer.java[tags=user_guide] +include::example$java/example/session/CloseableHttpServer.java[tags=user_guide] ---- <1> The `close()` method is called when the launcher session is closed <2> Stop the HTTP server @@ -163,7 +159,7 @@ by adding the file to `src/test/resources`): [source] .src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener ---- -include::{testResourcesDir}/META-INF/services/org.junit.platform.launcher.LauncherSessionListener[] +include::example$resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener[] ---- You can now use the resource from your test: @@ -173,7 +169,7 @@ You can now use the resource from your test: ---- package example.session; -include::{testDir}/example/session/HttpTests.java[tags=user_guide] +include::example$java/example/session/HttpTests.java[tags=user_guide] ---- <1> Retrieve the HTTP server instance from the store <2> Get the host string directly from the injected HTTP server instance @@ -182,7 +178,7 @@ include::{testDir}/example/session/HttpTests.java[tags=user_guide] <5> Check the status code of the response [[launcher-api-launcher-interceptors-custom]] -==== Registering a LauncherInterceptor +== Registering a LauncherInterceptor In order to intercept the creation of instances of `{Launcher}` and `{LauncherSessionListener}` and calls to the `discover` and `execute` methods of the @@ -206,11 +202,11 @@ the JUnit Platform to load test classes and engine implementations. [source,java] ---- -include::{testDir}/example/CustomLauncherInterceptor.java[tags=user_guide] +include::example$java/example/CustomLauncherInterceptor.java[tags=user_guide] ---- [[launcher-api-launcher-discovery-listeners-custom]] -==== Registering a LauncherDiscoveryListener +== Registering a LauncherDiscoveryListener In addition to specifying discovery listeners as part of a `{LauncherDiscoveryRequest}` or registering them programmatically via the `{Launcher}` API, custom @@ -224,7 +220,7 @@ For example, an `example.CustomLauncherDiscoveryListener` class implementing and registered automatically. [[launcher-api-listeners-custom]] -==== Registering a TestExecutionListener +== Registering a TestExecutionListener In addition to the public `{Launcher}` API method for registering test execution listeners programmatically, custom `{TestExecutionListener}` implementations will be discovered at @@ -237,7 +233,7 @@ For example, an `example.CustomTestExecutionListener` class implementing registered automatically. [[launcher-api-listeners-config]] -==== Configuring a TestExecutionListener +== Configuring a TestExecutionListener When a `{TestExecutionListener}` is registered programmatically via the `{Launcher}` API, the listener may provide programmatic ways for it to be configured -- for example, via its @@ -251,7 +247,7 @@ listener can then access the configuration parameters via the `TestPlan` supplie methods. See the `{UniqueIdTrackingListener}` for an example. [[launcher-api-listeners-custom-deactivation]] -==== Deactivating a TestExecutionListener +== Deactivating a TestExecutionListener Sometimes it can be useful to run a test suite _without_ certain execution listeners being active. For example, you might have custom a `{TestExecutionListener}` that sends the test @@ -276,12 +272,12 @@ supplied in the `LauncherDiscoveryRequest` that is passed to the `{Launcher}`. ==== [[launcher-api-listeners-custom-deactivation-pattern]] -===== Pattern Matching Syntax +=== Pattern Matching Syntax Refer to <> for details. [[launcher-api-launcher-config]] -==== Configuring the Launcher +== Configuring the Launcher If you require fine-grained control over automatic detection and registration of test engines and listeners, you may create an instance of `{LauncherConfig}` and supply that to @@ -290,11 +286,11 @@ built-in fluent _builder_ API, as demonstrated in the following example. [source,java,indent=0] ---- -include::{testDir}/example/UsingTheLauncherDemo.java[tags=launcherConfig] +include::example$java/example/UsingTheLauncherDemo.java[tags=launcherConfig] ---- [[launcher-api-dry-run-mode]] -==== Dry-Run Mode +== Dry-Run Mode When running tests via the `{Launcher}` API, you can enable _dry-run mode_ by setting the `junit.platform.execution.dryRun.enabled` <>. [[launcher-api-launcher-cancellation]] -==== Cancelling a Running Test Execution +== Cancelling a Running Test Execution The launcher API provides the ability to cancel a running test execution mid-flight while allowing engines to clean up resources. To request an execution to be cancelled, you need @@ -369,7 +365,7 @@ failed can be achieved as follows. [source,java,indent=0] ---- -include::{testDir}/example/UsingTheLauncherDemo.java[tags=cancellation] +include::example$java/example/UsingTheLauncherDemo.java[tags=cancellation] ---- <1> Create a `{CancellationToken}` <2> Implement a `{TestExecutionListener}` that calls `cancel()` when a test fails From 42445c2ffac66d471514dcc9d4cd246635984935 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:16 +0100 Subject: [PATCH 40/57] Move engines.adoc to Antora module --- .../ROOT/pages}/advanced-topics/engines.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/advanced-topics/engines.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc b/documentation/modules/ROOT/pages/advanced-topics/engines.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc rename to documentation/modules/ROOT/pages/advanced-topics/engines.adoc From c374131c129f9fbcf6af22c7ac995f72e6b1051a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:17 +0100 Subject: [PATCH 41/57] Migrate engines.adoc to Antora syntax --- .../ROOT/pages/advanced-topics/engines.adoc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/engines.adoc b/documentation/modules/ROOT/pages/advanced-topics/engines.adoc index 8876443f0461..181d19656165 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/engines.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/engines.adoc @@ -1,5 +1,4 @@ -[[test-engines]] -=== Test Engines += Test Engines A `TestEngine` facilitates _discovery_ and _execution_ of tests for a particular programming model. @@ -8,7 +7,7 @@ For example, JUnit provides a `TestEngine` that discovers and executes tests wri the JUnit Jupiter programming model (see <> and <>). [[test-engines-junit]] -==== JUnit Test Engines +== JUnit Test Engines JUnit provides three `TestEngine` implementations. @@ -19,7 +18,7 @@ JUnit provides three `TestEngine` implementations. Platform launcher infrastructure. [[test-engines-custom]] -==== Custom Test Engines +== Custom Test Engines You can contribute your own custom `{TestEngine}` by implementing the interfaces in the {junit-platform-engine} module and _registering_ your engine. @@ -70,7 +69,7 @@ provide the logic for test discovery. It implements execution of `TestDescriptor implement the `Node` interface, including support for parallel execution. [[test-engines-registration]] -==== Registering a TestEngine +== Registering a TestEngine `TestEngine` registration is supported via Java's `{ServiceLoader}` mechanism. @@ -80,14 +79,14 @@ For example, the `junit-jupiter-engine` module registers its `junit-jupiter-engine` JAR. [[test-engines-requirements]] -==== Requirements +== Requirements NOTE: The words "must", "must not", "required", "shall", "shall not", "should", "should not", "recommended", "may", and "optional" in this section are to be interpreted as described in https://www.ietf.org/rfc/rfc2119.txt[RFC 2119.] [[test-engines-requirements-mandatory]] -===== Mandatory requirements +=== Mandatory requirements For interoperability with build tools and IDEs, `TestEngine` implementations must adhere to the following requirements: @@ -108,7 +107,7 @@ to the following requirements: reported for its descendants. [[test-engines-requirements-enhanced-compatibility]] -===== Enhanced compatibility +=== Enhanced compatibility Adhering to the following requirements is optional but recommended for enhanced compatibility with build tools and IDEs: @@ -131,7 +130,7 @@ compatibility with build tools and IDEs: that it has created just like if execution had finished regularly. [[test-engines-discovery-issues]] -==== Reporting Discovery Issues +== Reporting Discovery Issues Test engines should report <> if they encounter any problems or potential misconfigurations during test discovery. This is From 32c773fa74d6b99f1f164339835181bdbdbb1aeb Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:17 +0100 Subject: [PATCH 42/57] Add advanced topics to navigation --- documentation/modules/ROOT/nav.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 4f6e26390b2b..1001902474f3 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -54,3 +54,9 @@ ** xref:extensions/keeping-state-in-extensions.adoc[] ** xref:extensions/supported-utilities-in-extensions.adoc[] ** xref:extensions/relative-execution-order-of-user-code-and-extensions.adoc[] +* Advanced Topics +** xref:advanced-topics/junit-platform-reporting.adoc[] +** xref:advanced-topics/junit-platform-suite-engine.adoc[] +** xref:advanced-topics/testkit.adoc[] +** xref:advanced-topics/launcher-api.adoc[] +** xref:advanced-topics/engines.adoc[] From 873bca39e0968f6e833c88826067c915acfa7029 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:17 +0100 Subject: [PATCH 43/57] Move api-evolution.adoc to Antora module --- .../asciidoc/user-guide => modules/ROOT/pages}/api-evolution.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/api-evolution.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/api-evolution.adoc b/documentation/modules/ROOT/pages/api-evolution.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/api-evolution.adoc rename to documentation/modules/ROOT/pages/api-evolution.adoc From 218b471ec38d25bb3e6c0e7936afd75ddbe564da Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:17 +0100 Subject: [PATCH 44/57] Migrate api-evolution.adoc to Antora syntax --- documentation/modules/ROOT/pages/api-evolution.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/modules/ROOT/pages/api-evolution.adoc b/documentation/modules/ROOT/pages/api-evolution.adoc index 601299666251..448c4aff5c2c 100644 --- a/documentation/modules/ROOT/pages/api-evolution.adoc +++ b/documentation/modules/ROOT/pages/api-evolution.adoc @@ -1,5 +1,5 @@ -[[api-evolution]] -== API Evolution += API Evolution +:page-toclevels: 1 One of the major goals of the JUnit Platform architecture is to improve maintainers' capabilities to evolve JUnit despite its being used in many projects. With JUnit 4 a lot @@ -11,7 +11,7 @@ That's why JUnit now uses a defined lifecycle for all publicly available interfa classes, and methods. [[api-evolution-version-and-status]] -=== API Version and Status +== API Version and Status Every published artifact has a version number `..`, and all publicly available interfaces, classes, and methods are annotated with {API} from the @@ -39,7 +39,7 @@ public members of that type as well. A member is allowed to declare a different value of lower stability. [[api-evolution-experimental-apis]] -=== Experimental APIs +== Experimental APIs The following tables list which APIs are currently designated as _experimental_ via `@API(status = EXPERIMENTAL)`. Caution should be taken when relying on such APIs. @@ -47,7 +47,7 @@ The following tables list which APIs are currently designated as _experimental_ include::{experimentalApisTableFile}[] [[api-evolution-deprecated-apis]] -=== Deprecated APIs +== Deprecated APIs The following tables list which APIs are currently designated as _deprecated_ via `@API(status = DEPRECATED)`. You should avoid using deprecated APIs whenever possible, @@ -56,7 +56,7 @@ since such APIs will likely be removed in an upcoming release. include::{deprecatedApisTableFile}[] [[api-evolution-tooling]] -=== @API Tooling Support +== @API Tooling Support The {API_Guardian} project plans to provide tooling support for publishers and consumers of APIs annotated with {API}. For example, the tooling support will likely provide a From e37158d24a3b927bb4304754eb6a17f3f2ffda3b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:18 +0100 Subject: [PATCH 45/57] Add api-evolution.adoc to navigation --- documentation/modules/ROOT/nav.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 1001902474f3..947ca70d2a18 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -60,3 +60,4 @@ ** xref:advanced-topics/testkit.adoc[] ** xref:advanced-topics/launcher-api.adoc[] ** xref:advanced-topics/engines.adoc[] +* xref:api-evolution.adoc[] From 4a103997b009c054fcb3b6eebefefd56e2176c79 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:18 +0100 Subject: [PATCH 46/57] Remove Contributors link to GitHub --- documentation/src/docs/asciidoc/user-guide/contributors.adoc | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/user-guide/contributors.adoc diff --git a/documentation/src/docs/asciidoc/user-guide/contributors.adoc b/documentation/src/docs/asciidoc/user-guide/contributors.adoc deleted file mode 100644 index 00911583c4d3..000000000000 --- a/documentation/src/docs/asciidoc/user-guide/contributors.adoc +++ /dev/null @@ -1,4 +0,0 @@ -[[contributors]] -== Contributors - -Browse the {junit-framework-repo}/graphs/contributors[current list of contributors] directly on GitHub. From e1959322a2286f664fcdaedbcaebc06e64e0d8f6 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:18 +0100 Subject: [PATCH 47/57] Move release-notes.adoc to Antora module --- .../index.adoc => modules/ROOT/pages/release-notes.adoc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/release-notes/index.adoc => modules/ROOT/pages/release-notes.adoc} (100%) diff --git a/documentation/src/docs/asciidoc/release-notes/index.adoc b/documentation/modules/ROOT/pages/release-notes.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/index.adoc rename to documentation/modules/ROOT/pages/release-notes.adoc From 7ec05312c383cada75103bd8100af2768d082436 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:19 +0100 Subject: [PATCH 48/57] Migrate release-notes.adoc to Antora syntax --- .../modules/ROOT/pages/release-notes.adoc | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/documentation/modules/ROOT/pages/release-notes.adoc b/documentation/modules/ROOT/pages/release-notes.adoc index c7f8737025c6..d1577a11de8a 100644 --- a/documentation/modules/ROOT/pages/release-notes.adoc +++ b/documentation/modules/ROOT/pages/release-notes.adoc @@ -1,12 +1,6 @@ -[[release-notes]] -= JUnit Release Notes -Stefan Bechtold; Sam Brannen; Johannes Link; Matthias Merdes; Marc Philipp; Juliette de Rancourt; Christian Stein += Release Notes +:page-aliases: release-notes/index.adoc // -:basedir: {includedir}/release-notes -:docinfodir: {includedir}/docinfos -:docinfo2: -:numbered!: -:last-update-label!: // This document contains the change log for all JUnit releases since 6.0 GA. @@ -15,14 +9,12 @@ Please refer to the <<../user-guide/index.adoc#user-guide,User Guide>> for compr reference documentation for programmers writing tests, extension authors, and engine authors as well as build tool and IDE vendors. -include::{includedir}/link-attributes.adoc[] +include::partial$release-notes/release-notes-6.1.0-M2.adoc[] -include::{basedir}/release-notes-6.1.0-M2.adoc[] +include::partial$release-notes/release-notes-6.1.0-M1.adoc[] -include::{basedir}/release-notes-6.1.0-M1.adoc[] +include::partial$release-notes/release-notes-6.0.2.adoc[] -include::{basedir}/release-notes-6.0.2.adoc[] +include::partial$release-notes/release-notes-6.0.1.adoc[] -include::{basedir}/release-notes-6.0.1.adoc[] - -include::{basedir}/release-notes-6.0.0.adoc[] +include::partial$release-notes/release-notes-6.0.0.adoc[] From 4183ffb88c8d7bc07742961f06eca7a14bfb83bb Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:19 +0100 Subject: [PATCH 49/57] Add release-notes.adoc to navigation --- documentation/modules/ROOT/nav.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 947ca70d2a18..f94938523cb5 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -61,3 +61,4 @@ ** xref:advanced-topics/launcher-api.adoc[] ** xref:advanced-topics/engines.adoc[] * xref:api-evolution.adoc[] +* xref:release-notes.adoc[] From 057bb1b1b541785bebf7d0d2d4bf60941204428e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:19 +0100 Subject: [PATCH 50/57] Move individual release note files to Antora module --- .../ROOT/partials}/release-notes/release-notes-6.0.0.adoc | 0 .../ROOT/partials}/release-notes/release-notes-6.0.1.adoc | 0 .../ROOT/partials}/release-notes/release-notes-6.0.2.adoc | 0 .../ROOT/partials}/release-notes/release-notes-6.1.0-M1.adoc | 0 .../ROOT/partials}/release-notes/release-notes-6.1.0-M2.adoc | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-6.0.0.adoc (100%) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-6.0.1.adoc (100%) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-6.0.2.adoc (100%) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-6.1.0-M1.adoc (100%) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-6.1.0-M2.adoc (100%) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.1.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-6.0.1.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.2.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-6.0.2.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M1.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M1.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc From eee25cad4a8eb9018698547e1fa67097bfe06171 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:20 +0100 Subject: [PATCH 51/57] Move release-notes-TEMPLATE.adoc to Antora module --- .../ROOT/partials}/release-notes/release-notes-TEMPLATE.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc => modules/ROOT/partials}/release-notes/release-notes-TEMPLATE.adoc (100%) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-TEMPLATE.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc similarity index 100% rename from documentation/src/docs/asciidoc/release-notes/release-notes-TEMPLATE.adoc rename to documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc From 2b25d542442e6a63977dc5ba89bf67444fa87577 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:20 +0100 Subject: [PATCH 52/57] Migrate release-notes-TEMPLATE.adoc to Antora syntax --- .../ROOT/partials/release-notes/release-notes-TEMPLATE.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc index 5bd352c3c008..3861188d538e 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc @@ -10,7 +10,7 @@ // which you can determine via https://github.com/junit-team/junit-framework/milestones/. // If a GitHub milestone does not yet exist for the given VERSION, you will need to // create a new GitHub milestone or ask a member of the JUnit team to create it for you. -// 5) 'include:' this new file in index.adoc. +// 5) 'include:' this new file in ../../pages/release-notes.adoc. // 6) Delete this entire comment block. // [[release-notes-VERSION]] From c1ef601f7150997a28c914b6b8af657287fe7b37 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:20 +0100 Subject: [PATCH 53/57] Move appendix.adoc to Antora module --- .../docs/asciidoc/user-guide => modules/ROOT/pages}/appendix.adoc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{src/docs/asciidoc/user-guide => modules/ROOT/pages}/appendix.adoc (100%) diff --git a/documentation/src/docs/asciidoc/user-guide/appendix.adoc b/documentation/modules/ROOT/pages/appendix.adoc similarity index 100% rename from documentation/src/docs/asciidoc/user-guide/appendix.adoc rename to documentation/modules/ROOT/pages/appendix.adoc From 2fb0b440fe58573b8f9ad8093dcc34178f36272e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:21 +0100 Subject: [PATCH 54/57] Migrate appendix.adoc to Antora syntax --- .../modules/ROOT/pages/appendix.adoc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/documentation/modules/ROOT/pages/appendix.adoc b/documentation/modules/ROOT/pages/appendix.adoc index ea11c07b7dea..50139eca50c9 100644 --- a/documentation/modules/ROOT/pages/appendix.adoc +++ b/documentation/modules/ROOT/pages/appendix.adoc @@ -1,8 +1,7 @@ -[[appendix]] -== Appendix += Appendix [[reproducible-builds]] -=== Reproducible Builds +== Reproducible Builds JUnit aims for its non-javadoc JARs to be https://reproducible-builds.org/[reproducible]. @@ -14,7 +13,7 @@ Central/Sonatype and produce the same output artifact locally, confirming that t artifacts in the repositories were actually generated from this source code. [[dependency-metadata]] -=== Dependency Metadata +== Dependency Metadata Artifacts for final releases and milestones are deployed to {Maven_Central}. Consult https://central.sonatype.org/consume/[Sonatype's documentation] for how to consume those @@ -46,7 +45,7 @@ Please refer to the corresponding sections for < Date: Sun, 7 Dec 2025 17:03:21 +0100 Subject: [PATCH 55/57] Add appendix.adoc to navigation --- documentation/modules/ROOT/nav.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index f94938523cb5..568e8e4dc25a 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -62,3 +62,4 @@ ** xref:advanced-topics/engines.adoc[] * xref:api-evolution.adoc[] * xref:release-notes.adoc[] +* xref:appendix.adoc[] From a8eb0db298d568ea9de940fe3697812d0c679cc9 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:22 +0100 Subject: [PATCH 56/57] Fix links --- .../ROOT/pages/advanced-topics/engines.adoc | 30 ++--- .../junit-platform-reporting.adoc | 28 ++--- .../junit-platform-suite-engine.adoc | 16 +-- .../pages/advanced-topics/launcher-api.adoc | 64 +++++----- .../ROOT/pages/advanced-topics/testkit.adoc | 33 +++-- .../modules/ROOT/pages/api-evolution.adoc | 12 +- .../modules/ROOT/pages/appendix.adoc | 24 ++-- .../conditional-test-execution.adoc | 8 +- .../extensions/intercepting-invocations.adoc | 2 +- .../keeping-state-in-extensions.adoc | 10 +- .../extensions/parameter-resolution.adoc | 12 +- .../extensions/pre-interrupt-callback.adoc | 2 +- ...vocation-contexts-for-class-templates.adoc | 2 +- ...nvocation-contexts-for-test-templates.adoc | 4 +- .../extensions/registering-extensions.adoc | 60 +++++---- ...ion-order-of-user-code-and-extensions.adoc | 20 +-- .../supported-utilities-in-extensions.adoc | 16 +-- .../extensions/test-instance-factories.adoc | 2 +- .../test-instance-post-processing.adoc | 2 +- .../test-instance-pre-construct-callback.adoc | 2 +- .../extensions/test-lifecycle-callbacks.adoc | 8 +- .../extensions/test-result-processing.adoc | 4 +- .../ROOT/pages/migrating-from-junit4.adoc | 54 ++++---- .../modules/ROOT/pages/overview.adoc | 50 ++++---- .../modules/ROOT/pages/release-notes.adoc | 2 +- .../pages/running-tests/build-support.adoc | 52 ++++---- .../capturing-standard-output-error.adoc | 6 +- .../configuration-parameters.adoc | 28 ++--- .../pages/running-tests/console-launcher.adoc | 26 ++-- .../pages/running-tests/discovery-issues.adoc | 4 +- .../running-tests/discovery-selectors.adoc | 2 +- .../ROOT/pages/running-tests/ide-support.adoc | 12 +- .../ROOT/pages/running-tests/tags.adoc | 8 +- .../using-listeners-and-interceptors.adoc | 24 ++-- .../ROOT/pages/writing-tests/annotations.adoc | 54 ++++---- .../ROOT/pages/writing-tests/assertions.adoc | 6 +- .../writing-tests/built-in-extensions.adoc | 19 ++- .../pages/writing-tests/class-templates.adoc | 4 +- .../conditional-test-execution.adoc | 26 ++-- .../ROOT/pages/writing-tests/definitions.adoc | 3 +- ...njection-for-constructors-and-methods.adoc | 6 +- .../pages/writing-tests/disabling-tests.adoc | 3 +- .../pages/writing-tests/display-names.adoc | 10 +- .../pages/writing-tests/dynamic-tests.adoc | 12 +- .../writing-tests/exception-handling.adoc | 20 +-- .../pages/writing-tests/nested-tests.adoc | 4 +- .../writing-tests/parallel-execution.adoc | 24 ++-- .../parameterized-classes-and-tests.adoc | 118 +++++++++--------- .../pages/writing-tests/repeated-tests.adoc | 4 +- .../writing-tests/tagging-and-filtering.adoc | 6 +- .../test-classes-and-methods.adoc | 8 +- .../writing-tests/test-execution-order.adoc | 25 ++-- .../test-instance-lifecycle.adoc | 8 +- .../test-interfaces-and-default-methods.adoc | 6 +- .../pages/writing-tests/test-templates.adoc | 6 +- .../ROOT/pages/writing-tests/timeouts.adoc | 22 ++-- .../release-notes/release-notes-6.0.0.adoc | 2 +- .../release-notes/release-notes-6.0.1.adoc | 20 +-- .../release-notes/release-notes-6.0.2.adoc | 26 ++-- .../release-notes/release-notes-6.1.0-M1.adoc | 18 +-- .../release-notes/release-notes-6.1.0-M2.adoc | 28 ++--- .../release-notes/release-notes-TEMPLATE.adoc | 26 ++-- 62 files changed, 567 insertions(+), 576 deletions(-) diff --git a/documentation/modules/ROOT/pages/advanced-topics/engines.adoc b/documentation/modules/ROOT/pages/advanced-topics/engines.adoc index 181d19656165..c11272db9fd4 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/engines.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/engines.adoc @@ -4,9 +4,9 @@ A `TestEngine` facilitates _discovery_ and _execution_ of tests for a particular programming model. For example, JUnit provides a `TestEngine` that discovers and executes tests written using -the JUnit Jupiter programming model (see <> and <>). +the JUnit Jupiter programming model (see xref:writing-tests/intro.adoc[] and xref:extensions/overview.adoc[]). -[[test-engines-junit]] +[[junit]] == JUnit Test Engines JUnit provides three `TestEngine` implementations. @@ -17,7 +17,7 @@ JUnit provides three `TestEngine` implementations. * `{junit-platform-suite-engine}`: Executes declarative suites of tests with the JUnit Platform launcher infrastructure. -[[test-engines-custom]] +[[custom]] == Custom Test Engines You can contribute your own custom `{TestEngine}` by implementing the interfaces in the @@ -45,7 +45,7 @@ annotation. For example, the `@Test` and `@TestFactory` annotations in JUnit Jup meta-annotated with `@Testable`. Consult the Javadoc for `{Testable}` for further details. If your custom `TestEngine` needs to be configured, consider allowing users to supply -configuration via <>. Please note, +configuration via xref:running-tests/configuration-parameters.adoc[configuration parameters]. Please note, however, that you are strongly encouraged to use a unique prefix for all configuration parameters supported by your test engine. Doing so will ensure that there are no conflicts between the names of your configuration parameters and those from other test engines. In @@ -57,7 +57,7 @@ parameters. Furthermore, as with the warning above regarding the `junit-` prefix configuration parameters. Although there is currently no official guide on how to implement a custom `TestEngine`, -you can consult the implementation of <> or the implementation of +you can consult the implementation of <> or the implementation of third-party test engines listed in the https://github.com/junit-team/junit-framework/wiki/Third-party-Extensions#junit-platform-test-engines[JUnit wiki]. You will also find various tutorials and blogs on the Internet that demonstrate how to @@ -68,7 +68,7 @@ NOTE: `{HierarchicalTestEngine}` is a convenient abstract base implementation of provide the logic for test discovery. It implements execution of `TestDescriptors` that implement the `Node` interface, including support for parallel execution. -[[test-engines-registration]] +[[registration]] == Registering a TestEngine `TestEngine` registration is supported via Java's `{ServiceLoader}` mechanism. @@ -78,14 +78,14 @@ For example, the `junit-jupiter-engine` module registers its `org.junit.platform.engine.TestEngine` within the `/META-INF/services` folder in the `junit-jupiter-engine` JAR. -[[test-engines-requirements]] +[[requirements]] == Requirements NOTE: The words "must", "must not", "required", "shall", "shall not", "should", "should not", "recommended", "may", and "optional" in this section are to be interpreted as described in https://www.ietf.org/rfc/rfc2119.txt[RFC 2119.] -[[test-engines-requirements-mandatory]] +[[requirements-mandatory]] === Mandatory requirements For interoperability with build tools and IDEs, `TestEngine` implementations must adhere @@ -106,7 +106,7 @@ to the following requirements: after their children. If a node is reported as skipped, there _must not_ be any events reported for its descendants. -[[test-engines-requirements-enhanced-compatibility]] +[[requirements-enhanced-compatibility]] === Enhanced compatibility Adhering to the following requirements is optional but recommended for enhanced @@ -119,9 +119,9 @@ compatibility with build tools and IDEs: * When resolving `UniqueIdSelectors`, a `TestEngine` _should_ only return `TestDescriptor` instances with matching unique IDs including their ancestors but _may_ return additional siblings or other nodes that are required for the execution of the selected tests. -* `TestEngines` _should_ support <> tests and containers so +* `TestEngines` _should_ support xref:running-tests/tags.adoc[tagging] tests and containers so that tag filters can be applied when discovering tests. -* [[test-engines-requirements-cancellation]] A `TestEngine` _should_ cancel its execution +* [[requirements-cancellation]] A `TestEngine` _should_ cancel its execution when the `{CancellationToken}` it is passed as part of the `ExecutionRequest` indicates that cancellation has been requested. In this case, it _should_ report any remaining `TestDescriptors` as skipped but not report any events for their descendants. It _may_ @@ -129,10 +129,10 @@ compatibility with build tools and IDEs: completely. If a `TestEngine` supports cancellation, it should clean up any resources that it has created just like if execution had finished regularly. -[[test-engines-discovery-issues]] +[[discovery-issues]] == Reporting Discovery Issues -Test engines should report <> if they +Test engines should report xref:running-tests/discovery-issues.adoc[discovery issues] if they encounter any problems or potential misconfigurations during test discovery. This is especially important if the issue could lead to tests not being executed at all or only partially. @@ -143,7 +143,7 @@ In order to report a `{DiscoveryIssue}`, a test engine should call the listener around, the `{DiscoveryIssueReporter}` interface should be used. It also provides a way to create a `Condition` that reports a discovery issue if its check fails and may be used as a `Predicate` or `Consumer`. Please refer to the implementations of the -<> for examples. +<> for examples. -Moreover, <> provides a way to write tests for +Moreover, xref:advanced-topics/testkit.adoc#engine-discovery[Engine Test Kit] provides a way to write tests for reported discovery issues. diff --git a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc index 2c4d89c4b85a..fe74bef80896 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-reporting.adoc @@ -2,19 +2,19 @@ The `junit-platform-reporting` artifact contains `{TestExecutionListener}` implementations that generate XML test reports in two flavors: -<> and -<>. +<> and +<>. NOTE: The module also contains other `TestExecutionListener` implementations that can be -used to build custom reporting. See <> for details. +used to build custom reporting. See xref:running-tests/using-listeners-and-interceptors.adoc[] for details. -[[junit-platform-reporting-output-directory]] +[[output-directory]] == Output Directory The JUnit Platform provides an `{OutputDirectoryCreator}` via `{EngineDiscoveryRequest}` -and `{TestPlan}` to registered <> and -<>, respectively. Its root directory can be configured -via the following <>: +and `{TestPlan}` to registered xref:advanced-topics/engines.adoc[test engines] and +xref:running-tests/using-listeners-and-interceptors.adoc[listeners], respectively. Its root directory can be configured +via the following xref:running-tests/configuration-parameters.adoc[configuration parameter]: `junit.platform.reporting.output.dir=`:: Configure the output directory for reporting. By default, `build` is used if a Gradle @@ -27,7 +27,7 @@ directories like `reports/junit-8803697269315188212`. This can be useful when us Gradle's or Maven's parallel execution capabilities which create multiple JVM forks that run concurrently. -[[junit-platform-reporting-open-test-reporting]] +[[open-test-reporting]] == Open Test Reporting `{OpenTestReportGeneratingListener}` writes an XML report for the entire execution in the @@ -35,7 +35,7 @@ event-based format specified by {OpenTestReporting} which supports all features JUnit Platform such as hierarchical test structures, display names, tags, etc. The listener is auto-registered and can be configured via the following -<>: +xref:running-tests/configuration-parameters.adoc[configuration parameters]: `junit.platform.reporting.open.xml.enabled=true|false`:: Enable/disable writing the report; defaults to `false`. @@ -47,11 +47,11 @@ The listener is auto-registered and can be configured via the following connection is automatically closed when the test execution completes. If enabled, the listener creates an XML report file named `open-test-report.xml` in the -configured <>, unless the +configured <>, unless the `junit.platform.reporting.open.xml.socket` configuration parameter is set, in which case the events are sent to the specified socket instead. -If <> is enabled, the captured output +If xref:running-tests/capturing-standard-output-error.adoc[output capturing] is enabled, the captured output written to `System.out` and `System.err` will be included in the report as well. TIP: The {OpenTestReportingCliTool} can be used to convert from the event-based format to @@ -142,7 +142,7 @@ XML reports as follows: === Console Launcher -When using the <>, you can enable Open Test Reporting +When using the xref:running-tests/console-launcher.adoc[], you can enable Open Test Reporting output by setting the configuration parameters via `--config`: [source,console,subs=attributes+] @@ -161,12 +161,12 @@ $ java -jar junit-platform-console-standalone-{version}.jar \ --config-resource=configuration.properties ---- -[[junit-platform-reporting-legacy-xml]] +[[legacy-xml]] == Legacy XML format `{LegacyXmlReportGeneratingListener}` generates a separate XML report for each root in the `{TestPlan}`. Note that the generated XML format is compatible with the de facto standard for JUnit 4 based test reports that was made popular by the Ant build system. -The `LegacyXmlReportGeneratingListener` is used by the <> +The `LegacyXmlReportGeneratingListener` is used by the xref:running-tests/console-launcher.adoc[] as well. diff --git a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc index 5262d1332bee..8466f1fa2c62 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/junit-platform-suite-engine.adoc @@ -1,18 +1,18 @@ = JUnit Platform Suite Engine The Suite Engine supports the declarative selection and execution of tests from _any_ test -engine on the JUnit Platform using the <>. +engine on the JUnit Platform using the xref:advanced-topics/launcher-api.adoc[]. image::junit-platform-suite-engine-diagram.svg[role=text-center] -[[junit-platform-suite-engine-setup]] +[[setup]] == Setup In addition to the `junit-platform-suite-api` and `junit-platform-suite-engine` artifacts, you need _at least one_ other test engine and its dependencies on the classpath. See -<> for details regarding group IDs, artifact IDs, and versions. +xref:appendix.adoc#dependency-metadata[Dependency Metadata] for details regarding group IDs, artifact IDs, and versions. -[[junit-platform-suite-engine-setup-required-dependencies]] +[[setup-required-dependencies]] === Required Dependencies * `junit-platform-suite-api` in _test_ scope: artifact containing annotations needed to @@ -24,7 +24,7 @@ NOTE: Both of the required dependencies are aggregated in the `junit-platform-su artifact which can be declared in _test_ scope instead of declaring explicit dependencies on `junit-platform-suite-api` and `junit-platform-suite-engine`. -[[junit-platform-suite-engine-setup-transitive-dependencies]] +[[setup-transitive-dependencies]] === Transitive Dependencies * `junit-platform-launcher` in _test_ scope @@ -32,7 +32,7 @@ on `junit-platform-suite-api` and `junit-platform-suite-engine`. * `junit-platform-commons` in _test_ scope * `opentest4j` in _test_ scope -[[junit-platform-suite-engine-example]] +[[example]] == @Suite Example Annotate a class with `@Suite` to have it marked as a test suite on the JUnit Platform. As @@ -60,7 +60,7 @@ suite, respectively. include::example$java/example/BeforeAndAfterSuiteDemo.java[tags=user_guide] ---- -[[junit-platform-suite-engine-duplicate-test-execution]] +[[duplicate-test-execution]] == Duplicate Test Execution Depending on the declared selectors, different suites may contain the same tests, @@ -75,5 +75,5 @@ include only the `junit-platform-suite` engine, or use a custom naming pattern. example, name all suites `*Suite` and all tests `*Test`, and configure your build tool to include only the former. -Alternatively, consider <> to select specific groups of +Alternatively, consider xref:running-tests/tags.adoc[using tags] to select specific groups of tests. diff --git a/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc b/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc index ac57b65a254c..903591aabb82 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/launcher-api.adoc @@ -8,7 +8,7 @@ filtering and configuration that is necessary from the outside. JUnit Platform provides a `Launcher` API that can be used to discover, filter, and execute tests. Moreover, third party test libraries – like Spock or Cucumber – can plug into the JUnit Platform's launching infrastructure by providing a custom -<>. +xref:advanced-topics/engines.adoc[TestEngine]. image::launcher-api-diagram.svg[role=text-center] @@ -17,7 +17,7 @@ The launcher API is in the `{junit-platform-launcher}` module. An example consumer of the launcher API is the `{ConsoleLauncher}` in the `{junit-platform-console}` project. -[[launcher-api-discovery]] +[[discovery]] == Discovering Tests Having _test discovery_ as a dedicated feature of the platform frees IDEs and build tools @@ -51,10 +51,10 @@ Clients can register one or more `{LauncherDiscoveryListener}` implementations v discovery. By default, the builder registers an "abort on failure" listener that aborts test discovery after the first discovery failure is encountered. The default `LauncherDiscoveryListener` can be changed via the -`junit.platform.discovery.listener.default` <>. +`junit.platform.discovery.listener.default` xref:running-tests/configuration-parameters.adoc[configuration +parameter]. -[[launcher-api-execution]] +[[execution]] == Executing Tests To execute tests, clients can use the same `LauncherDiscoveryRequest` as in the discovery @@ -77,13 +77,13 @@ events are called in registration order while methods for finish events are call reverse order. Test case execution won't start before all `executionStarted` calls have returned. -[[launcher-api-engines-custom]] +[[engines-custom]] == Registering a TestEngine -See the dedicated section on <> for +See the dedicated section on xref:advanced-topics/engines.adoc#registration[TestEngine registration] for details. -[[launcher-api-post-discovery-filters-custom]] +[[post-discovery-filters-custom]] == Registering a PostDiscoveryFilter In addition to specifying post-discovery filters as part of a `{LauncherDiscoveryRequest}` @@ -95,7 +95,7 @@ For example, an `example.CustomTagFilter` class implementing `PostDiscoveryFilte declared within the `/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter` file is loaded and applied automatically. -[[launcher-api-launcher-session-listeners-custom]] +[[launcher-session-listeners-custom]] == Registering a LauncherSessionListener Registered implementations of `{LauncherSessionListener}` are notified when a @@ -105,7 +105,7 @@ programmatically via the `{LauncherConfig}` that is passed to the `{LauncherFact they can be discovered at runtime via Java's `{ServiceLoader}` mechanism and automatically registered with `LauncherSession` (unless automatic registration is disabled.) -[[launcher-api-launcher-session-listeners-tool-support]] +[[launcher-session-listeners-tool-support]] === Tool Support The following build tools and IDEs are known to provide full support for `LauncherSession`: @@ -116,7 +116,7 @@ The following build tools and IDEs are known to provide full support for `Launch Other tools might also work but have not been tested explicitly. -[[launcher-api-launcher-session-listeners-tool-example-usage]] +[[launcher-session-listeners-tool-example-usage]] === Example Usage A `LauncherSessionListener` is well suited for implementing once-per-JVM setup/teardown @@ -177,22 +177,21 @@ include::example$java/example/session/HttpTests.java[tags=user_guide] <4> Send a request to the server <5> Check the status code of the response -[[launcher-api-launcher-interceptors-custom]] +[[launcher-interceptors-custom]] == Registering a LauncherInterceptor In order to intercept the creation of instances of `{Launcher}` and `{LauncherSessionListener}` and calls to the `discover` and `execute` methods of the former, clients can register custom implementations of `{LauncherInterceptor}` via Java's `{ServiceLoader}` mechanism by setting the -`junit.platform.launcher.interceptors.enabled` <> to `true`. +`junit.platform.launcher.interceptors.enabled` xref:running-tests/configuration-parameters.adoc[configuration parameter] to `true`. [NOTE] ==== Since interceptors are registered before the test run starts, the `junit.platform.launcher.interceptors.enabled` _configuration parameter_ can only be supplied as a JVM system property or via the JUnit Platform configuration file (see -<> for details). This _configuration parameter_ cannot be +xref:running-tests/configuration-parameters.adoc[] for details). This _configuration parameter_ cannot be supplied in the `LauncherDiscoveryRequest` that is passed to the `{Launcher}`. ==== @@ -205,7 +204,7 @@ the JUnit Platform to load test classes and engine implementations. include::example$java/example/CustomLauncherInterceptor.java[tags=user_guide] ---- -[[launcher-api-launcher-discovery-listeners-custom]] +[[launcher-discovery-listeners-custom]] == Registering a LauncherDiscoveryListener In addition to specifying discovery listeners as part of a `{LauncherDiscoveryRequest}` or @@ -219,7 +218,7 @@ For example, an `example.CustomLauncherDiscoveryListener` class implementing `/META-INF/services/org.junit.platform.launcher.LauncherDiscoveryListener` file is loaded and registered automatically. -[[launcher-api-listeners-custom]] +[[listeners-custom]] == Registering a TestExecutionListener In addition to the public `{Launcher}` API method for registering test execution listeners @@ -232,21 +231,21 @@ For example, an `example.CustomTestExecutionListener` class implementing `/META-INF/services/org.junit.platform.launcher.TestExecutionListener` file is loaded and registered automatically. -[[launcher-api-listeners-config]] +[[listeners-config]] == Configuring a TestExecutionListener When a `{TestExecutionListener}` is registered programmatically via the `{Launcher}` API, the listener may provide programmatic ways for it to be configured -- for example, via its constructor, setter methods, etc. However, when a `TestExecutionListener` is registered automatically via Java's `ServiceLoader` mechanism (see -<>), there is no way for the user to directly configure the +<>), there is no way for the user to directly configure the listener. In such cases, the author of a `TestExecutionListener` may choose to make the -listener configurable via <>. The +listener configurable via xref:running-tests/configuration-parameters.adoc[configuration parameters]. The listener can then access the configuration parameters via the `TestPlan` supplied to the `testPlanExecutionStarted(TestPlan)` and `testPlanExecutionFinished(TestPlan)` callback methods. See the `{UniqueIdTrackingListener}` for an example. -[[launcher-api-listeners-custom-deactivation]] +[[listeners-custom-deactivation]] == Deactivating a TestExecutionListener Sometimes it can be useful to run a test suite _without_ certain execution listeners being @@ -267,16 +266,16 @@ deactivated. In other words, any `TestExecutionListener` registered explicitly v In addition, since execution listeners are registered before the test run starts, the `junit.platform.execution.listeners.deactivate` _configuration parameter_ can only be supplied as a JVM system property or via the JUnit Platform configuration file (see -<> for details). This _configuration parameter_ cannot be +xref:running-tests/configuration-parameters.adoc[] for details). This _configuration parameter_ cannot be supplied in the `LauncherDiscoveryRequest` that is passed to the `{Launcher}`. ==== -[[launcher-api-listeners-custom-deactivation-pattern]] +[[listeners-custom-deactivation-pattern]] === Pattern Matching Syntax -Refer to <> for details. +Refer to xref:running-tests/configuration-parameters.adoc#pattern[Pattern Matching Syntax] for details. -[[launcher-api-launcher-config]] +[[launcher-config]] == Configuring the Launcher If you require fine-grained control over automatic detection and registration of test @@ -289,18 +288,17 @@ built-in fluent _builder_ API, as demonstrated in the following example. include::example$java/example/UsingTheLauncherDemo.java[tags=launcherConfig] ---- -[[launcher-api-dry-run-mode]] +[[dry-run-mode]] == Dry-Run Mode When running tests via the `{Launcher}` API, you can enable _dry-run mode_ by setting the -`junit.platform.execution.dryRun.enabled` <> to `true`. In this mode, the `{Launcher}` will not actually +`junit.platform.execution.dryRun.enabled` xref:running-tests/configuration-parameters.adoc[configuration parameter] to `true`. In this mode, the `{Launcher}` will not actually execute any tests but will notify registered `{TestExecutionListener}` instances as if all tests had been skipped and their containers had been successful. This can be useful to test changes in the configuration of a build or to verify a listener is called as expected without having to wait for all tests to be executed. -[[launcher-api-managing-state-across-test-engines]] +[[managing-state-across-test-engines]] == Managing State Across Test Engines When running tests on the JUnit Platform, multiple test engines may need to access shared @@ -350,9 +348,9 @@ way, test engines can coordinate resource creation and sharing without direct de between them. Alternatively, it's possible to inject resources into test engines by -<>. +<>. -[[launcher-api-launcher-cancellation]] +[[launcher-cancellation]] == Cancelling a Running Test Execution The launcher API provides the ability to cancel a running test execution mid-flight while @@ -376,9 +374,9 @@ include::example$java/example/UsingTheLauncherDemo.java[tags=cancellation] [NOTE] .Test Engine Support for Cancellation ==== -Cancelling tests relies on <> checking and responding to the +Cancelling tests relies on xref:advanced-topics/engines.adoc[] checking and responding to the `{CancellationToken}` appropriately (see -<> for details). The +xref:advanced-topics/engines.adoc#requirements-cancellation[Test Engine Requirements] for details). The `Launcher` will also check the token and cancel test execution when multiple test engines are present at runtime. diff --git a/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc b/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc index 6910b8bea154..7900df1623d8 100644 --- a/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc +++ b/documentation/modules/ROOT/pages/advanced-topics/testkit.adoc @@ -2,9 +2,9 @@ The `junit-platform-testkit` artifact provides support for executing a test plan on the JUnit Platform and then verifying the expected results. This support is currently limited -to the execution of a single `TestEngine` (see <>). +to the execution of a single `TestEngine` (see <>). -[[testkit-engine]] +[[engine]] == Engine Test Kit The `{testkit-engine-package}` package provides support for discovering and executing a @@ -21,7 +21,7 @@ to build your `LauncherDiscoveryRequest`, you must use one of the `discover()` o The following test class written using JUnit Jupiter will be used in subsequent examples. -[[testkit-engine-ExampleTestCase]] +[[engine-ExampleTestCase]] [source,java,indent=0] ---- include::example$java/example/ExampleTestCase.java[tags=user_guide] @@ -33,7 +33,7 @@ own `TestEngine` implementation, you need to use its unique engine ID. Alternati may test your own `TestEngine` by supplying an instance of it to the `EngineTestKit.engine(TestEngine)` static factory method. -[[testkit-engine-discovery]] +[[engine-discovery]] == Verifying Test Discovery The following test demonstrates how to verify that a `TestPlan` was discovered as expected @@ -44,12 +44,12 @@ by the JUnit Jupiter `TestEngine`. include::example$java/example/testkit/EngineTestKitDiscoveryDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. -<2> Select the <> test class. +<2> Select the <> test class. <3> Discover the `TestPlan`. <4> Assert engine root descriptor has expected display name. <5> Assert no discovery issues were encountered. -[[testkit-engine-statistics]] +[[engine-statistics]] == Asserting Execution Statistics One of the most common features of the Test Kit is the ability to assert statistics @@ -62,7 +62,7 @@ For details on what statistics are available, consult the Javadoc for `{EventSta include::example$java/example/testkit/EngineTestKitStatisticsDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. -<2> Select the <> test class. +<2> Select the <> test class. <3> Execute the `TestPlan`. <4> Filter by _container_ events. <5> Assert statistics for _container_ events. @@ -71,17 +71,17 @@ include::example$java/example/testkit/EngineTestKitStatisticsDemo.java[tags=user NOTE: In the `verifyJupiterContainerStats()` test method, the counts for the `started` and `succeeded` statistics are `2` since the `JupiterTestEngine` and the -<> class are both considered containers. +<> class are both considered containers. -[[testkit-engine-events]] +[[engine-events]] == Asserting Events -If you find that <> alone is insufficient +If you find that <> alone is insufficient for verifying the expected behavior of test execution, you can work directly with the recorded `{Event}` elements and perform assertions against them. For example, if you want to verify the reason that the `skippedTest()` method in -<> was skipped, you can do that as +<> was skipped, you can do that as follows. [TIP] @@ -99,8 +99,7 @@ events, consult the Javadoc for `{EventConditions}`. include::example$java/example/testkit/EngineTestKitSkippedMethodDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. -<2> Select the `skippedTest()` method in the <> test class. +<2> Select the `skippedTest()` method in the <> test class. <3> Execute the `TestPlan`. <4> Filter by _test_ events. <5> Save the _test_ `Events` to a local variable. @@ -109,7 +108,7 @@ include::example$java/example/testkit/EngineTestKitSkippedMethodDemo.java[tags=u `skippedTest` with `"for demonstration purposes"` as the _reason_. If you want to verify the type of exception thrown from the `failingTest()` method in -<>, you can do that as follows. +<>, you can do that as follows. [TIP] ==== @@ -123,7 +122,7 @@ events and execution results, consult the Javadoc for `{EventConditions}` and include::example$java/example/testkit/EngineTestKitFailedMethodDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. -<2> Select the <> test class. +<2> Select the <> test class. <3> Execute the `TestPlan`. <4> Filter by _test_ events. <5> Assert that the recorded _test_ events contain exactly one failing test named @@ -137,7 +136,7 @@ achieve this via the `assertEventsMatchExactly()` method in the `EngineTestKit` [TIP] ==== Since `assertEventsMatchExactly()` matches conditions exactly in the order in which the -events were fired, <> has been +events were fired, <> has been annotated with `@TestMethodOrder(OrderAnnotation.class)` and each test method has been annotated with `@Order(...)`. This allows us to enforce the order in which the test methods are executed, which in turn allows our `verifyAllJupiterEvents()` test to be @@ -153,7 +152,7 @@ respectively. include::example$java/example/testkit/EngineTestKitAllEventsDemo.java[tags=user_guide] ---- <1> Select the JUnit Jupiter `TestEngine`. -<2> Select the <> test class. +<2> Select the <> test class. <3> Execute the `TestPlan`. <4> Filter by _all_ events. <5> Print all events to the supplied `writer` for debugging purposes. Debug information diff --git a/documentation/modules/ROOT/pages/api-evolution.adoc b/documentation/modules/ROOT/pages/api-evolution.adoc index 448c4aff5c2c..87570809f5f7 100644 --- a/documentation/modules/ROOT/pages/api-evolution.adoc +++ b/documentation/modules/ROOT/pages/api-evolution.adoc @@ -10,7 +10,7 @@ sometimes impossible. That's why JUnit now uses a defined lifecycle for all publicly available interfaces, classes, and methods. -[[api-evolution-version-and-status]] +[[version-and-status]] == API Version and Status Every published artifact has a version number `..`, and all publicly @@ -38,24 +38,24 @@ If the `@API` annotation is present on a type, it is considered to be applicable public members of that type as well. A member is allowed to declare a different `status` value of lower stability. -[[api-evolution-experimental-apis]] +[[experimental-apis]] == Experimental APIs The following tables list which APIs are currently designated as _experimental_ via `@API(status = EXPERIMENTAL)`. Caution should be taken when relying on such APIs. -include::{experimentalApisTableFile}[] +include::partial$experimental-apis-table.adoc[] -[[api-evolution-deprecated-apis]] +[[deprecated-apis]] == Deprecated APIs The following tables list which APIs are currently designated as _deprecated_ via `@API(status = DEPRECATED)`. You should avoid using deprecated APIs whenever possible, since such APIs will likely be removed in an upcoming release. -include::{deprecatedApisTableFile}[] +include::partial$deprecated-apis-table.adoc[] -[[api-evolution-tooling]] +[[tooling]] == @API Tooling Support The {API_Guardian} project plans to provide tooling support for publishers and consumers diff --git a/documentation/modules/ROOT/pages/appendix.adoc b/documentation/modules/ROOT/pages/appendix.adoc index 50139eca50c9..4cb40e7240bd 100644 --- a/documentation/modules/ROOT/pages/appendix.adoc +++ b/documentation/modules/ROOT/pages/appendix.adoc @@ -36,12 +36,12 @@ of the above artifacts and their versions. ==== To ensure that all JUnit artifacts are compatible with each other, their versions should be aligned. -If you rely on <> for dependency management, +If you rely on xref:running-tests/build-support.adoc#spring-boot[Spring Boot] for dependency management, please see the corresponding section. Otherwise, instead of managing individual versions of the JUnit artifacts, it is recommended to apply the <> to your project. -Please refer to the corresponding sections for <> or -<>. +Please refer to the corresponding sections for xref:running-tests/build-support.adoc#maven-bom[Maven] or +xref:running-tests/build-support.adoc#gradle-bom[Gradle]. ==== [[dependency-metadata-junit-platform]] @@ -56,29 +56,29 @@ Please refer to the corresponding sections for <> for details. + See xref:running-tests/console-launcher.adoc[] for details. `junit-platform-console-standalone`:: An executable _Fat JAR_ that contains all dependencies is provided in Maven Central under the https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] - directory. See <> for details. + directory. See xref:running-tests/console-launcher.adoc[] for details. `junit-platform-engine`:: - Public API for test engines. See <> for details. + Public API for test engines. See xref:advanced-topics/launcher-api.adoc#engines-custom[Registering a TestEngine] for details. `junit-platform-launcher`:: Public API for configuring and launching test plans -- typically used by IDEs and - build tools. See <> for details. + build tools. See xref:advanced-topics/launcher-api.adoc[] for details. `junit-platform-reporting`:: `TestExecutionListener` implementations that generate test reports -- typically used - by IDEs and build tools. See <> for details. + by IDEs and build tools. See xref:advanced-topics/junit-platform-reporting.adoc[] for details. `junit-platform-suite`:: JUnit Platform Suite artifact that transitively pulls in dependencies on `junit-platform-suite-api` and `junit-platform-suite-engine` for simplified dependency management in build tools such as Gradle and Maven. `junit-platform-suite-api`:: Annotations for configuring test suites on the JUnit Platform. Supported by the - <>. + xref:advanced-topics/junit-platform-suite-engine.adoc[JUnit Platform Suite Engine]. `junit-platform-suite-engine`:: Engine that executes test suites on the JUnit Platform; only required at runtime. See - <> for details. + xref:advanced-topics/junit-platform-suite-engine.adoc[JUnit Platform Suite Engine] for details. `junit-platform-testkit`:: Provides support for executing a test plan for a given `TestEngine` and then accessing the results via a fluent API to verify the expected results. @@ -94,11 +94,11 @@ Please refer to the corresponding sections for <> and <>. + JUnit Jupiter API for xref:writing-tests/intro.adoc[writing tests] and xref:extensions/overview.adoc[extensions]. `junit-jupiter-engine`:: JUnit Jupiter test engine implementation; only required at runtime. `junit-jupiter-params`:: - Support for <> in JUnit Jupiter. + Support for xref:writing-tests/parameterized-classes-and-tests.adoc[] in JUnit Jupiter. `junit-jupiter-migrationsupport`:: _Deprecated_ support for migrating from JUnit 4 to JUnit Jupiter; only required for support for JUnit 4's `@Ignore` annotation and for running selected JUnit 4 rules. diff --git a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc index 8efca7980733..45a3e7cb5a41 100644 --- a/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/extensions/conditional-test-execution.adoc @@ -17,7 +17,7 @@ short-circuiting boolean OR operator. See the source code of `{DisabledCondition}` and `{Disabled}` for concrete examples. -[[extensions-conditions-deactivation]] +[[deactivation]] == Deactivating Conditions Sometimes it can be useful to run a test suite _without_ certain conditions being active. @@ -27,14 +27,14 @@ order to see if they are still _broken_. To do this, provide a pattern for the conditions should be deactivated (i.e., not evaluated) for the current test run. The pattern can be supplied as a JVM system property, as a _configuration parameter_ in the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). +configuration file (see xref:running-tests/configuration-parameters.adoc[] for details). For example, to deactivate JUnit's `@Disabled` condition, you can start your JVM with the following system property. `-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition` -[[extensions-conditions-deactivation-patterns]] +[[deactivation-patterns]] === Pattern Matching Syntax -Refer to <> for details. +Refer to xref:running-tests/configuration-parameters.adoc#pattern[Pattern Matching Syntax] for details. diff --git a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc index c78e1edc00e5..b3090668d4d3 100644 --- a/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc +++ b/documentation/modules/ROOT/pages/extensions/intercepting-invocations.adoc @@ -17,6 +17,6 @@ include::example$java/example/interceptor/SwingEdtInterceptor.java[tags=user_gui ==== You may override the `getTestInstantiationExtensionContextScope(...)` method to return `TEST_METHOD` to make test-specific data available to your extension implementation of -`interceptTestClassConstructor` or if you want to <> +`interceptTestClassConstructor` or if you want to xref:extensions/keeping-state-in-extensions.adoc[keep state] on the test method level. ==== diff --git a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc index 5017884c73f5..082da03fa2ed 100644 --- a/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/keeping-state-in-extensions.adoc @@ -5,7 +5,7 @@ you keep the state from one invocation of an extension to the next? The `{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose. Extensions may put values into a store for later retrieval. -TIP: See the `<>` for an +TIP: See the `xref:extensions/test-lifecycle-callbacks.adoc#timing-extension[TimingExtension]` for an example of using the `Store` with a method-level scope. .The `ExtensionContext` and `Store` hierarchy @@ -20,11 +20,11 @@ classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyo that and access the stores on the level of the current `{LauncherExecutionRequest}` or `{LauncherSession}` which can be used to share data across test engines or inject data from a registered -<>, +xref:advanced-topics/launcher-api.adoc#launcher-session-listeners-custom[`LauncherSessionListener`], respectively. Please consult the Javadoc of `{ExtensionContext}`, `{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details. -[[extensions-keeping-state-autocloseable-support]] +[[support]] [NOTE] .Resource management via `_AutoCloseable_` ==== @@ -34,7 +34,7 @@ context lifecycle ends it closes its associated store. All stored values that are instances of `AutoCloseable` are notified by an invocation of their `close()` method in the inverse order they were added in (unless the `junit.jupiter.extensions.store.close.autocloseable.enabled` -<> is set to `false`). +xref:running-tests/configuration-parameters.adoc[configuration parameter] is set to `false`). Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still available for backward compatibility. @@ -67,7 +67,7 @@ include::example$java/example/extensions/HttpServerExtension.java[tags=user_guid include::example$java/example/HttpServerDemo.java[tags=user_guide] ---- -[[extensions-keeping-state-autocloseable-migration]] +[[migration]] [TIP] .Migration Note for Resource Cleanup ==== diff --git a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc index c626f20c8530..da61a5a67bce 100644 --- a/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc +++ b/documentation/modules/ROOT/pages/extensions/parameter-resolution.adoc @@ -4,9 +4,9 @@ runtime. If a _test class_ constructor, _test method_, or _lifecycle method_ (see -<>) declares a parameter, the parameter must be _resolved_ at +xref:writing-tests/definitions.adoc[]) declares a parameter, the parameter must be _resolved_ at runtime by a `ParameterResolver`. A `ParameterResolver` can either be built-in (see -`{TestInfoParameterResolver}`) or <>. +`{TestInfoParameterResolver}`) or xref:extensions/registering-extensions.adoc[registered by the user]. Generally speaking, parameters may be resolved by _name_, _type_, _annotation_, or any combination thereof. @@ -41,7 +41,7 @@ You may override the `getTestInstantiationExtensionContextScope(...)` method to `TEST_METHOD` to support injecting test specific data into constructor parameters of the test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while resolving constructor parameters, unless the -<> is set to `PER_CLASS`. +xref:writing-tests/test-instance-lifecycle.adoc[test instance lifecycle] is set to `PER_CLASS`. ==== [TIP] @@ -52,7 +52,7 @@ constructor invocations, using the `{ExecutableInvoker}` available via the `getExecutableInvoker()` method in the `ExtensionContext`. ==== -[[extensions-parameter-resolution-conflicts]] +[[conflicts]] == Parameter Conflicts If multiple implementations of `ParameterResolver` that support the same type are @@ -95,10 +95,10 @@ include::example$java/example/extensions/ParameterResolverCustomAnnotationDemo.j JUnit includes some built-in parameter resolvers that can cause conflicts if a resolver attempts to claim their supported types. For example, `{TestInfo}` provides metadata about -tests. See <> for details. Third-party frameworks such +tests. See xref:writing-tests/dependency-injection-for-constructors-and-methods.adoc[] for details. Third-party frameworks such as Spring may also define parameter resolvers. Apply one of the techniques in this section to resolve any conflicts. Parameterized tests are another potential source of conflict. Ensure that tests annotated with `@ParameterizedTest` are not also annotated with `@Test` and see -<> for more details. +xref:writing-tests/parameterized-classes-and-tests.adoc#tests-consuming-arguments[Consuming Arguments] for more details. diff --git a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc index 5e61a03abe74..d046c1e29a4e 100644 --- a/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/pre-interrupt-callback.adoc @@ -3,4 +3,4 @@ `{PreInterruptCallback}` defines the API for `Extensions` that wish to react on timeouts before the `Thread.interrupt()` is called. -Please refer to <> for additional information. +Please refer to xref:writing-tests/timeouts.adoc#debugging[Debugging Timeouts] for additional information. diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc index f111450665bc..fa1b7936b10a 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-class-templates.adoc @@ -37,5 +37,5 @@ methods in a test class albeit in different contexts — for example, with diffe parameters, by preparing the test class instance differently, or multiple times without modifying the context. Please refer to the implementations of -<> which uses this extension +xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Classes] which uses this extension point to provide its functionality. diff --git a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc index b7b488180b5b..2d55a58a5ae3 100644 --- a/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc +++ b/documentation/modules/ROOT/pages/extensions/providing-invocation-contexts-for-test-templates.adoc @@ -30,6 +30,6 @@ The `{TestTemplateInvocationContextProvider}` extension API is primarily intende implementing different kinds of tests that rely on repetitive invocation of a test-like method albeit in different contexts — for example, with different parameters, by preparing the test class instance differently, or multiple times without modifying the context. -Please refer to the implementations of <> or -<> which use this extension point +Please refer to the implementations of xref:writing-tests/repeated-tests.adoc[] or +xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Tests] which use this extension point to provide their functionality. diff --git a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc index d7d9dedbf39b..e25eb404f063 100644 --- a/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/registering-extensions.adoc @@ -1,16 +1,16 @@ = Registering Extensions Extensions can be registered _declaratively_ via -<>, _programmatically_ via -<>, or _automatically_ via -Java's <> mechanism. +<>, _programmatically_ via +<>, or _automatically_ via +Java's <> mechanism. -[[extensions-registration-declarative]] +[[registration-declarative]] == Declarative Extension Registration Developers can register one or more extensions _declaratively_ by annotating a test -interface, test class, test method, or custom _<>_ with `@ExtendWith(...)` and supplying class references for the extensions to +interface, test class, test method, or custom _xref:writing-tests/annotations.adoc#annotations[composed +annotation]_ with `@ExtendWith(...)` and supplying class references for the extensions to register. `@ExtendWith` may also be declared on fields or on parameters in test class constructors, in test methods, and in `@BeforeAll`, `@AfterAll`, `@BeforeEach`, and `@AfterEach` lifecycle methods. @@ -72,7 +72,7 @@ be extended by the `DatabaseExtension` and `WebServerExtension`, **in exactly th ==== If you wish to combine multiple extensions in a reusable way, you can define a custom -_<>_ and use `@ExtendWith` as a +_xref:writing-tests/annotations.adoc#annotations[composed annotation]_ and use `@ExtendWith` as a _meta-annotation_ as in the following code listing. Then `@DatabaseAndWebServerExtension` can be used in place of `@ExtendWith({ DatabaseExtension.class, WebServerExtension.class })`. @@ -104,7 +104,7 @@ include::example$java/example/extensions/Random.java[tags=user_guide] include::example$java/example/extensions/RandomNumberDemo.java[tags=user_guide] ---- -[[extensions-RandomNumberExtension]] +[[RandomNumberExtension]] The following code listing provides an example of how one might choose to implement such a `RandomNumberExtension`. This implementation works for the use cases in `RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for @@ -129,8 +129,7 @@ include::example$java/example/extensions/RandomNumberExtension.java[tags=user_gu Extensions registered declaratively via `@ExtendWith` on fields will be ordered relative to `@RegisterExtension` fields and other `@ExtendWith` fields using an algorithm that is deterministic but intentionally nonobvious. However, `@ExtendWith` fields can be ordered -using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. +using the `@Order` annotation. See the <> tip for `@RegisterExtension` fields for details. ==== [TIP] @@ -139,27 +138,27 @@ Extension Registration Order>> tip for `@RegisterExtension` fields for details. Extensions registered declaratively via `@ExtendWith` on fields in superclasses will be inherited. -See <> for details. +See <> for details. ==== NOTE: `@ExtendWith` fields may be either `static` or non-static. The documentation on -<> and -<> for +<> and +<> for `@RegisterExtension` fields also applies to `@ExtendWith` fields. -[[extensions-registration-programmatic]] +[[registration-programmatic]] == Programmatic Extension Registration Developers can register extensions _programmatically_ by annotating fields in test classes with `{RegisterExtension}`. When an extension is registered _declaratively_ via -<>, it can typically only be configured +<>, it can typically only be configured via annotations. In contrast, when an extension is registered via `@RegisterExtension`, it can be configured _programmatically_ -- for example, in order to pass arguments to the extension's constructor, a static factory method, or a builder API. -[[extensions-registration-programmatic-order]] +[[registration-programmatic-order]] [TIP] .Extension Registration Order ==== @@ -188,13 +187,13 @@ relative to other programmatically registered extensions. Extensions registered via `@RegisterExtension` or `@ExtendWith` on fields in superclasses will be inherited. -See <> for details. +See <> for details. ==== NOTE: `@RegisterExtension` fields must not be `null` (at evaluation time) but may be either `static` or non-static. -[[extensions-registration-programmatic-static-fields]] +[[registration-programmatic-static-fields]] === Static Fields If a `@RegisterExtension` field is `static`, the extension will be registered after @@ -220,7 +219,7 @@ lifecycle methods annotated with `@BeforeAll` or `@AfterAll` as well as `@Before include::example$java/example/registration/WebServerDemo.java[tags=user_guide] ---- -[[extensions-registration-programmatic-static-fields-kotlin]] +[[registration-programmatic-static-fields-kotlin]] ==== Static Fields in Kotlin The Kotlin programming language does not have the concept of a `static` field. However, @@ -237,7 +236,7 @@ has been ported to Kotlin. include::example$kotlin/example/registration/KotlinWebServerDemo.kt[tags=user_guide] ---- -[[extensions-registration-programmatic-instance-fields]] +[[registration-programmatic-instance-fields]] === Instance Fields If a `@RegisterExtension` field is non-static (i.e., an instance field), the extension @@ -262,11 +261,11 @@ instance of the extension via the `docs` field if necessary. include::example$java/example/registration/DocumentationDemo.java[tags=user_guide] ---- -[[extensions-registration-automatic]] +[[registration-automatic]] == Automatic Extension Registration -In addition to <> -and <> support +In addition to <> +and <> support using annotations, JUnit Jupiter also supports _global extension registration_ via Java's `{ServiceLoader}` mechanism, allowing third-party extensions to be auto-detected and automatically registered based on what is available in the classpath. @@ -275,14 +274,14 @@ Specifically, a custom extension can be registered by supplying its fully qualif name in a file named `org.junit.jupiter.api.extension.Extension` within the `/META-INF/services` folder in its enclosing JAR file. -[[extensions-registration-automatic-enabling]] +[[registration-automatic-enabling]] === Enabling Automatic Extension Detection Auto-detection is an advanced feature and is therefore not enabled by default. To enable it, set the `junit.jupiter.extensions.autodetection.enabled` _configuration parameter_ to `true`. This can be supplied as a JVM system property, as a _configuration parameter_ in the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). +configuration file (see xref:running-tests/configuration-parameters.adoc[] for details). For example, to enable auto-detection of extensions, you can start your JVM with the following system property. @@ -293,11 +292,11 @@ When auto-detection is enabled, extensions discovered via the `{ServiceLoader}` will be added to the extension registry after JUnit Jupiter's global extensions (e.g., support for `TestInfo`, `TestReporter`, etc.). -[[extensions-registration-automatic-filtering]] +[[registration-automatic-filtering]] === Filtering Auto-detected Extensions The list of auto-detected extensions can be filtered using include and exclude patterns -via the following <>: +via the following xref:running-tests/configuration-parameters.adoc[configuration parameters]: `junit.jupiter.extensions.autodetection.include=`:: Comma-separated list of _include_ patterns for auto-detected extensions. @@ -308,9 +307,9 @@ Include patterns are applied _before_ exclude patterns. If both include and excl patterns are provided, only extensions that match at least one include pattern and do not match any exclude pattern will be auto-detected. -See <> for details on the pattern syntax. +See xref:running-tests/configuration-parameters.adoc#pattern[Pattern Matching Syntax] for details on the pattern syntax. -[[extensions-registration-inheritance]] +[[registration-inheritance]] == Extension Inheritance Registered extensions are inherited within test class hierarchies with top-down semantics. @@ -324,8 +323,7 @@ be registered before extensions registered declaratively via `@ExtendWith` on a Similarly, extensions registered programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a superclass will be registered before extensions registered programmatically via `@RegisterExtension` or `@ExtendWith` on fields in a subclass, unless -`@Order` is used to alter that behavior (see <> for details). +`@Order` is used to alter that behavior (see <> for details). NOTE: A specific extension implementation can only be registered once for a given extension context and its parent contexts. Consequently, any attempt to register a diff --git a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc index f062f7987df0..6c88a1ed6d29 100644 --- a/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/relative-execution-order-of-user-code-and-extensions.adoc @@ -3,9 +3,9 @@ When executing a test class that contains one or more test methods, a number of extension callbacks are called in addition to the user-supplied test and lifecycle methods. -NOTE: See also: <> +NOTE: See also: xref:writing-tests/test-execution-order.adoc[] -[[extensions-execution-order-overview]] +[[overview]] == User and Extension Code The following diagram illustrates the relative order of user-supplied code and extension @@ -13,12 +13,12 @@ code. User-supplied test and lifecycle methods are shown in orange, with callbac implemented by extensions shown in blue. The grey box denotes the execution of a single test method and will be repeated for every test method in the test class. -[[extensions-execution-order-diagram]] +[[diagram]] .User code and extension code image::extensions_lifecycle.png[] The following table further explains the sixteen steps in the -<> diagram. +<> diagram. . *interface* `*org.junit.jupiter.api.extension.BeforeAllCallback*` + extension code executed before all tests of the container are executed @@ -29,7 +29,7 @@ user code executed before all tests of the container are executed extension code for handling exceptions thrown from `@BeforeAll` methods . *interface* `*org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback*` + extension code executed before each class template invocation is executed (only applicable -if the test class is a <>) +if the test class is a xref:writing-tests/class-templates.adoc[class template]) . *interface* `*org.junit.jupiter.api.extension.BeforeEachCallback*` + extension code executed before each test is executed . *annotation* `*org.junit.jupiter.api.BeforeEach*` + @@ -54,7 +54,7 @@ extension code for handling exceptions thrown from `@AfterEach` methods extension code executed after each test is executed . *interface* `*org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback*` + extension code executed after each class template invocation is executed (only applicable -if the test class is a <>) +if the test class is a xref:writing-tests/class-templates.adoc[class template]) . *annotation* `*org.junit.jupiter.api.AfterAll*` + user code executed after all tests of the container are executed . *interface* `*org.junit.jupiter.api.extension.LifecycleMethodExecutionExceptionHandler @@ -69,9 +69,9 @@ corresponding lifecycle callback. For further details on the various lifecycle c please consult the respective Javadoc for each annotation and extension. All invocations of user code methods in the above table can additionally be intercepted -by implementing <>. +by implementing xref:extensions/intercepting-invocations.adoc[`InvocationInterceptor`]. -[[extensions-execution-order-wrapping-behavior]] +[[wrapping-behavior]] == Wrapping Behavior of Callbacks JUnit Jupiter always guarantees _wrapping_ behavior for multiple registered extensions @@ -89,7 +89,7 @@ callbacks implemented by `Extension2`. `Extension1` is therefore said to _wrap_ `Extension2`. JUnit Jupiter also guarantees _wrapping_ behavior within class and interface hierarchies -for user-supplied _lifecycle methods_ (see <>). +for user-supplied _lifecycle methods_ (see xref:writing-tests/definitions.adoc[]). * `@BeforeAll` methods are inherited from superclasses as long as they are not _overridden_. Furthermore, `@BeforeAll` methods from superclasses will be executed @@ -233,6 +233,6 @@ image::extensions_BrokenLifecycleMethodConfigDemo.png[caption='',title='BrokenLi [TIP] ==== Due to the aforementioned behavior, the JUnit Team recommends that developers declare at -most one of each type of _lifecycle method_ (see <>) per test +most one of each type of _lifecycle method_ (see xref:writing-tests/definitions.adoc[]) per test class or test interface unless there are no dependencies between such lifecycle methods. ==== diff --git a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc index 38ca96625bab..bacf8790a3e2 100644 --- a/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/extensions/supported-utilities-in-extensions.adoc @@ -6,7 +6,7 @@ utilities can be found in the `{junit-platform-support-package}` and its subpack `TestEngine` and `Extension` authors are encouraged to use these supported utilities in order to align with the behavior of the JUnit Platform and JUnit Jupiter. -[[extensions-supported-utilities-annotations]] +[[annotations]] == Annotation Support `AnnotationSupport` provides static utility methods that operate on annotated elements @@ -20,15 +20,15 @@ interfaces and within class hierarchies to find annotations. Consult the Javadoc NOTE: The `isAnnotated()` methods do not find repeatable annotations. To check for repeatable annotations, use one of the `findRepeatableAnnotations()` methods and verify that the returned list is not empty. -NOTE: See also: <> +NOTE: See also: <> -[[extensions-supported-utilities-classes]] +[[classes]] == Class Support `ClassSupport` provides static utility methods for working with classes (i.e., instances of `java.lang.Class`). Consult the Javadoc for `{ClassSupport}` for further details. -[[extensions-supported-utilities-reflection]] +[[reflection]] == Reflection Support `ReflectionSupport` provides static utility methods that augment the standard JDK @@ -38,9 +38,9 @@ class, and to find and invoke methods. Some of these methods traverse class hier to locate matching methods. Consult the Javadoc for `{ReflectionSupport}` for further details. -NOTE: See also: <> +NOTE: See also: <> -[[extensions-supported-utilities-modifier]] +[[modifier]] == Modifier Support `ModifierSupport` provides static utility methods for working with member and class @@ -48,7 +48,7 @@ modifiers -- for example, to determine if a member is declared as `public`, `pri `abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further details. -[[extensions-supported-utilities-conversion]] +[[conversion]] == Conversion Support `ConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) @@ -57,7 +57,7 @@ wrapper types, date and time types from the `java.time package`, and some additi common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, `URL`, `UUID`, etc. Consult the Javadoc for `{ConversionSupport}` for further details. -[[extensions-supported-utilities-search-semantics]] +[[search-semantics]] == Field and Method Search Semantics Various methods in `AnnotationSupport` and `ReflectionSupport` use search algorithms that diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc index 1682268d2ae5..0710cf755f42 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-factories.adoc @@ -28,5 +28,5 @@ registered for any specific test class. ==== You may override the `getTestInstantiationExtensionContextScope(...)` method to return `TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. +you want to xref:extensions/keeping-state-in-extensions.adoc[keep state] on the test method level. ==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc index 41b8b3b3de28..93bab7eaac29 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-post-processing.adoc @@ -14,5 +14,5 @@ For a concrete example, consult the source code for the `{MockitoExtension}` and ==== You may override the `getTestInstantiationExtensionContextScope(...)` method to return `TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. +you want to xref:extensions/keeping-state-in-extensions.adoc[keep state] on the test method level. ==== diff --git a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc index 4d4623367526..0d72d10018f2 100644 --- a/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-instance-pre-construct-callback.adoc @@ -13,5 +13,5 @@ instances and their lifecycle. ==== You may override the `getTestInstantiationExtensionContextScope(...)` method to return `TEST_METHOD` to make test-specific data available to your extension implementation or if -you want to <> on the test method level. +you want to xref:extensions/keeping-state-in-extensions.adoc[keep state] on the test method level. ==== diff --git a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc index f0782ab64c31..2b0190598f5e 100644 --- a/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-lifecycle-callbacks.adoc @@ -6,13 +6,13 @@ each of these interfaces in the `{extension-api-package}` package for further de * `{BeforeAllCallback}` ** `{BeforeClassTemplateInvocationCallback}` (only applicable for - <>) + xref:writing-tests/class-templates.adoc[class templates]) *** `{BeforeEachCallback}` **** `{BeforeTestExecutionCallback}` **** `{AfterTestExecutionCallback}` *** `{AfterEachCallback}` ** `{AfterClassTemplateInvocationCallback}` (only applicable for - <>) + xref:writing-tests/class-templates.adoc[class templates]) * `{AfterAllCallback}` .Implementing Multiple Extension APIs @@ -20,7 +20,7 @@ NOTE: Extension developers may choose to implement any number of these interface within a single extension. Consult the source code of the `{SpringExtension}` for a concrete example. -[[extensions-lifecycle-callbacks-before-after-execution]] +[[before-after-execution]] == Before and After Test Execution Callbacks `{BeforeTestExecutionCallback}` and `{AfterTestExecutionCallback}` define the APIs for @@ -34,7 +34,7 @@ The following example shows how to use these callbacks to calculate and log the time of a test method. `TimingExtension` implements both `BeforeTestExecutionCallback` and `AfterTestExecutionCallback` in order to time and log the test execution. -[[extensions-lifecycle-callbacks-timing-extension]] +[[timing-extension]] [source,java,indent=0] .An extension that times and logs the execution of test methods ---- diff --git a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc index c3d0f7503a1b..24fa7d04315e 100644 --- a/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc +++ b/documentation/modules/ROOT/pages/extensions/test-result-processing.adoc @@ -10,7 +10,7 @@ information for the following events. * `testFailed`: invoked after a _test method_ has failed NOTE: In contrast to the definition of "test method" presented in -<>, in this context _test method_ refers to any `@Test` method +xref:writing-tests/definitions.adoc[], in this context _test method_ refers to any `@Test` method or `@TestTemplate` method (for example, a `@RepeatedTest` or `@ParameterizedTest`). Extensions implementing this interface can be registered at the class level, instance @@ -46,6 +46,6 @@ or fail test execution. ==== Any instances of `ExtensionContext.Store.CloseableResource` stored in the `Store` of the provided `{ExtensionContext}` will be closed _before_ methods in the `TestWatcher` API are -invoked (see <>). You can use the parent context's `Store` to +invoked (see xref:extensions/keeping-state-in-extensions.adoc[]). You can use the parent context's `Store` to work with such resources. ==== diff --git a/documentation/modules/ROOT/pages/migrating-from-junit4.adoc b/documentation/modules/ROOT/pages/migrating-from-junit4.adoc index b0442759aad1..679b8b59acd7 100644 --- a/documentation/modules/ROOT/pages/migrating-from-junit4.adoc +++ b/documentation/modules/ROOT/pages/migrating-from-junit4.adoc @@ -13,7 +13,7 @@ classpath does not lead to any conflicts. It is therefore safe to maintain exist 4 tests alongside JUnit Jupiter tests and migrate them gradually. -[[migrating-from-junit4-running]] +[[running]] == Running JUnit 4 Tests on the JUnit Platform [WARNING] @@ -23,10 +23,10 @@ migrating tests to JUnit Jupiter or another testing framework with native JUnit support. By default, if the JUnit Vintage engine is registered and discovers at least one test -class, it reports a <> of INFO severity. +class, it reports a xref:running-tests/discovery-issues.adoc[discovery issue] of INFO severity. You can prevent this discovery issue from being reported by setting the `junit.vintage.discovery.issue.reporting.enabled` -<> to `false`. +xref:running-tests/configuration-parameters.adoc[configuration parameter] to `false`. ==== Make sure that the `junit-vintage-engine` artifact is in your test runtime path. In that @@ -36,23 +36,23 @@ launcher. See the example projects in the {junit-examples-repo}[`junit-examples`] repository to find out how this is done with Gradle and Maven. -[[migrating-from-junit4-categories-support]] +[[categories-support]] === Categories Support For test classes or methods that are annotated with `@Category`, the _JUnit Vintage test -engine_ exposes the category's fully qualified class name as a <> +engine_ exposes the category's fully qualified class name as a xref:running-tests/tags.adoc[tag] for the corresponding test class or test method. For example, if a test method is annotated with `@Category(Example.class)`, it will be tagged with `"com.acme.Example"`. Similar to the `Categories` runner in JUnit 4, this information can be used to filter the -discovered tests before executing them (see <> for details). +discovered tests before executing them (see xref:running-tests/intro.adoc[] for details). -[[migrating-from-junit4-parallel-execution]] +[[parallel-execution]] == Parallel Execution The JUnit Vintage test engine supports parallel execution of top-level test classes and test methods, allowing existing JUnit 3 and JUnit 4 tests to benefit from improved performance through concurrent test execution. It can be enabled and configured using the following -<>: +xref:running-tests/configuration-parameters.adoc[configuration parameters]: `junit.vintage.execution.parallel.enabled=true|false`:: Enable/disable parallel execution (defaults to `false`). Requires opt-in for `classes` @@ -68,7 +68,7 @@ concurrent test execution. It can be enabled and configured using the following Specifies the size of the thread pool to be used for parallel execution. By default, the number of available processors is used. -[[migrating-from-junit4-parallel-execution-class-level]] +[[parallel-execution-class-level]] === Parallelization at Class Level Let's assume we have two test classes `FooTest` and `BarTest` with each class containing @@ -93,7 +93,7 @@ ForkJoinPool-1-worker-1 - BarTest::test3 ForkJoinPool-1-worker-2 - FooTest::test3 ---- -[[migrating-from-junit4-parallel-execution-method-level]] +[[parallel-execution-method-level]] === Parallelization at Method Level Alternatively, we can enable parallel test execution at a method level, @@ -119,7 +119,7 @@ ForkJoinPool-1-worker-2 - FooTest::test2 ForkJoinPool-1-worker-1 - FooTest::test3 ---- -[[migrating-from-junit4-parallel-execution-class-and-method-level]] +[[parallel-execution-class-and-method-level]] === Full Parallelization Finally, we can also enable parallelization at both class and method level: @@ -144,7 +144,7 @@ ForkJoinPool-1-worker-5 - BarTest::test2 ForkJoinPool-1-worker-4 - BarTest::test1 ---- -[[migrating-from-junit4-parallel-execution-pool-size]] +[[parallel-execution-pool-size]] === Configuring the Pool Size The default thread pool size is equal to the number of available processors. However, we @@ -176,7 +176,7 @@ As we can see, even though we set the thread pool size was four, only three thre used in this case. This happens because the pool adjusts the number of active threads based on workload and system needs. -[[migrating-from-junit4-parallel-execution-disabled]] +[[parallel-execution-disabled]] === Sequential Execution On the other hand, if we disable parallel execution, the `VintageTestEngine` @@ -192,7 +192,7 @@ junit.vintage.execution.parallel.methods=true Similarly, tests will be executed sequentially if you enable parallel execution in general but enable neither class-level nor method-level parallelization. -[[migrating-from-junit4-tips]] +[[tips]] == Migration Tips The following are topics that you should be aware of when migrating existing JUnit 4 @@ -211,29 +211,29 @@ tests to JUnit Jupiter. * `@BeforeClass` and `@AfterClass` no longer exist; use `@BeforeAll` and `@AfterAll` instead. * `@Ignore` no longer exists: use `@Disabled` or one of the other built-in - <> instead - - See also <>. + xref:writing-tests/conditional-test-execution.adoc[execution conditions] instead + - See also <>. * `@Category` no longer exists; use `@Tag` instead. * `@RunWith` no longer exists; superseded by `@ExtendWith`. - For `@RunWith(Enclosed.class)` use `@Nested`. - - For `@RunWith(Parameterized.class)` see <>. + - For `@RunWith(Parameterized.class)` see <>. * `@Rule` and `@ClassRule` no longer exist; superseded by `@ExtendWith` and `@RegisterExtension`. - - See also <>. + - See also <>. * `@Test(expected = ...)` and the `ExpectedException` rule no longer exist; use `Assertions.assertThrows(...)` instead. - - See <> if you still need to use + - See <> if you still need to use `ExpectedException`. * Assertions and assumptions in JUnit Jupiter accept the failure message as their last argument instead of the first one. - - See <> for details. + - See <> for details. -[[migrating-from-junit4-tips-parameterized]] +[[tips-parameterized]] === Parameterized test classes Unless `@UseParametersRunnerFactory` is used, a JUnit 4 parameterized test class can be converted into a JUnit Jupiter -<> by following these steps: +xref:writing-tests/parameterized-classes-and-tests.adoc[`@ParameterizedClass`] by following these steps: . Replace `@RunWith(Parameterized.class)` with `@ParameterizedClass`. . Add a class-level `@MethodSource("methodName")` annotation where `methodName` is the @@ -261,7 +261,7 @@ include::example$java/example/ParameterizedMigrationDemo.java[tags=after] ---- ==== -[[migrating-from-junit4-rule-support]] +[[rule-support]] == Limited JUnit 4 Rule Support WARNING: _JUnit 4 rule support_ is deprecated for removal since version 6.0.0. Please @@ -292,13 +292,13 @@ This limited form of `Rule` support can be switched on by the class-level annota all rule migration support extensions: `VerifierSupport`, `ExternalResourceSupport`, and `ExpectedExceptionSupport`. You may alternatively choose to annotate your test class with `@EnableJUnit4MigrationSupport` which registers migration support for rules _and_ JUnit -4's `@Ignore` annotation (see <>). +4's `@Ignore` annotation (see <>). However, if you intend to develop a new extension for JUnit Jupiter please use the new extension model of JUnit Jupiter instead of the rule-based model of JUnit 4. -[[migrating-from-junit4-ignore-annotation-support]] +[[ignore-annotation-support]] == JUnit 4 @Ignore Support WARNING: _JUnit 4 `@Ignore` support_ is deprecated for removal since version 6.0.0. Please @@ -312,7 +312,7 @@ To use `@Ignore` with JUnit Jupiter based tests, configure a _test_ dependency o `junit-jupiter-migrationsupport` module in your build and then annotate your test class with `@ExtendWith(IgnoreCondition.class)` or `{EnableJUnit4MigrationSupport}` (which automatically registers the `IgnoreCondition` along with -<>). The `IgnoreCondition` is an +<>). The `IgnoreCondition` is an `{ExecutionCondition}` that disables test classes or test methods that are annotated with `@Ignore`. @@ -322,7 +322,7 @@ include::example$java/example/IgnoredTestsDemo.java[tags=user_guide] ---- -[[migrating-from-junit4-failure-message-arguments]] +[[failure-message-arguments]] == Failure Message Arguments The `Assumptions` and `Assertions` classes in JUnit Jupiter declare arguments in a diff --git a/documentation/modules/ROOT/pages/overview.adoc b/documentation/modules/ROOT/pages/overview.adoc index a5f27923123c..5a48feea6e43 100644 --- a/documentation/modules/ROOT/pages/overview.adoc +++ b/documentation/modules/ROOT/pages/overview.adoc @@ -11,26 +11,26 @@ This document is also available as a link:{userGuidePdfFileName}[PDF download]. endif::linkToPdf[] endif::backend-html5[] -[[overview-what-is-junit]] +[[what-is-junit]] == What is JUnit? JUnit is composed of several different modules from three different sub-projects. **JUnit {version} = _JUnit Platform_ + _JUnit Jupiter_ + _JUnit Vintage_** -The **JUnit Platform** serves as a foundation for <> on the JVM. It also defines the `{TestEngine}` API for developing a testing +The **JUnit Platform** serves as a foundation for xref:advanced-topics/launcher-api.adoc[launching testing +frameworks] on the JVM. It also defines the `{TestEngine}` API for developing a testing framework that runs on the platform. Furthermore, the platform provides a -<> to launch the platform from the -command line and the <> for running a custom test suite using +xref:running-tests/console-launcher.adoc[Console Launcher] to launch the platform from the +command line and the xref:advanced-topics/junit-platform-suite-engine.adoc[] for running a custom test suite using one or more test engines on the platform. First-class support for the JUnit Platform also -exists in popular IDEs (see <>, -<>, <>, and -<>) and build tools (see <>, -<>, and <>). +exists in popular IDEs (see xref:running-tests/ide-support.adoc#intellij-idea[IntelliJ IDEA], +xref:running-tests/ide-support.adoc#eclipse[Eclipse], xref:running-tests/ide-support.adoc#netbeans[NetBeans], and +xref:running-tests/ide-support.adoc#vscode[Visual Studio Code]) and build tools (see xref:running-tests/build-support.adoc#gradle[Gradle], +xref:running-tests/build-support.adoc#maven[Maven], and xref:running-tests/build-support.adoc#ant[Ant]). -**JUnit Jupiter** is the combination of the <> and -<> for writing JUnit tests and extensions. The Jupiter +**JUnit Jupiter** is the combination of the xref:writing-tests/intro.adoc[programming model] and +xref:extensions/overview.adoc[extension model] for writing JUnit tests and extensions. The Jupiter sub-project provides a `TestEngine` for running Jupiter based tests on the platform. **JUnit Vintage** provides a `TestEngine` for running JUnit 3 and JUnit 4 based tests on @@ -39,42 +39,42 @@ path. Note, however, that the JUnit Vintage engine is deprecated and should only temporarily while migrating tests to JUnit Jupiter or another testing framework with native JUnit Platform support. -[[overview-java-versions]] +[[java-versions]] == Supported Java Versions JUnit requires Java 17 (or higher) at runtime. However, you can still test code that has been compiled with previous versions of the JDK. -[[overview-getting-help]] +[[getting-help]] == Getting Help Ask JUnit-related questions on {StackOverflow} or use the {DiscussionsQA}. -[[overview-getting-started]] +[[getting-started]] == Getting Started -[[overview-getting-started-junit-artifacts]] +[[getting-started-junit-artifacts]] === Downloading JUnit Artifacts To find out what artifacts are available for download and inclusion in your project, refer -to <>. To set up dependency management for your build, refer to -<> and the <>. +to xref:appendix.adoc#dependency-metadata[Dependency Metadata]. To set up dependency management for your build, refer to +xref:running-tests/build-support.adoc[] and the <>. -[[overview-getting-started-features]] +[[getting-started-features]] === JUnit Features To find out what features are available in JUnit {version} and how to use them, read the corresponding sections of this User Guide, organized by topic. -* <> -* <> -* <> -* <> +* xref:writing-tests/intro.adoc[Writing Tests in JUnit Jupiter] +* xref:migrating-from-junit4.adoc[Migrating from JUnit 4 to JUnit Jupiter] +* xref:running-tests/intro.adoc[] +* xref:extensions/overview.adoc[Extension Model for JUnit Jupiter] * Advanced Topics - - <> - - <> + - xref:advanced-topics/launcher-api.adoc[] + - xref:advanced-topics/testkit.adoc[] -[[overview-getting-started-example-projects]] +[[getting-started-example-projects]] === Example Projects To see complete, working examples of projects that you can copy and experiment with, the diff --git a/documentation/modules/ROOT/pages/release-notes.adoc b/documentation/modules/ROOT/pages/release-notes.adoc index d1577a11de8a..f816e5a663dd 100644 --- a/documentation/modules/ROOT/pages/release-notes.adoc +++ b/documentation/modules/ROOT/pages/release-notes.adoc @@ -5,7 +5,7 @@ This document contains the change log for all JUnit releases since 6.0 GA. -Please refer to the <<../user-guide/index.adoc#user-guide,User Guide>> for comprehensive +Please refer to the xref:overview.adoc[User Guide] for comprehensive reference documentation for programmers writing tests, extension authors, and engine authors as well as build tool and IDE vendors. diff --git a/documentation/modules/ROOT/pages/running-tests/build-support.adoc b/documentation/modules/ROOT/pages/running-tests/build-support.adoc index dcb14a1d1ec0..36978dcb5559 100644 --- a/documentation/modules/ROOT/pages/running-tests/build-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/build-support.adoc @@ -1,6 +1,6 @@ = Build Support -[[running-tests-build-gradle]] +[[gradle]] == Gradle Starting with https://docs.gradle.org/4.6/release-notes.html[version 4.6], Gradle provides @@ -16,8 +16,8 @@ test { } ---- -Filtering by <>, -<>, or engines is also supported: +Filtering by xref:running-tests/tags.adoc[tags], +xref:running-tests/tags.adoc#expressions[tag expressions], or engines is also supported: [source,groovy,indent=0] [subs=attributes+] @@ -36,14 +36,14 @@ Please refer to the https://docs.gradle.org/current/userguide/java_testing.html[official Gradle documentation] for a comprehensive list of options. -[[running-tests-build-gradle-bom]] +[[gradle-bom]] === Aligning dependency versions -TIP: See <> for details on how to override the version +TIP: See <> for details on how to override the version of JUnit used in your Spring Boot application. Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the +recommended to use the JUnit Platform xref:appendix.adoc#dependency-metadata-junit-bom[Bill of Materials (BOM)] to align the versions of all JUnit artifacts. [source,groovy,indent=0] @@ -87,11 +87,11 @@ dependency on `junit-platform-launcher`, it is recommended to do so to ensure th of JUnit artifacts on the test runtime classpath are aligned. Moreover, doing so is recommended and in some cases even required when importing the -project into an IDE like <> or -<>. +project into an IDE like xref:running-tests/ide-support.adoc#eclipse[Eclipse] or +xref:running-tests/ide-support.adoc#intellij-idea[IntelliJ IDEA]. ==== -[[running-tests-build-gradle-engines-configure]] +[[gradle-engines-configure]] === Configuring Test Engines In order to run any tests at all, a `TestEngine` implementation must be on the classpath. @@ -152,11 +152,11 @@ dependencies { } ---- -[[running-tests-build-gradle-config-params]] +[[gradle-config-params]] === Configuration Parameters The standard Gradle `test` task currently does not provide a dedicated DSL to set JUnit -Platform <> to influence test +Platform xref:running-tests/configuration-parameters.adoc[configuration parameters] to influence test discovery and execution. However, you can provide configuration parameters within the build script via system properties (as shown below) or via the `junit-platform.properties` file. @@ -172,7 +172,7 @@ test { } ---- -[[running-tests-build-gradle-logging]] +[[gradle-logging]] === Configuring Logging (optional) JUnit uses the Java Logging APIs in the `java.util.logging` package (a.k.a. _JUL_) to @@ -201,7 +201,7 @@ Other logging frameworks provide different means to redirect messages logged usi https://www.slf4j.org/legacy.html#jul-to-slf4j[JUL to SLF4J Bridge] by adding it as a dependency to the test runtime classpath. -[[running-tests-build-maven]] +[[maven]] == Maven Maven Surefire and Maven Failsafe provide @@ -216,11 +216,11 @@ and can serve as a starting point for configuring your Maven build. As of JUnit 6.0, the minimum required version of Maven Surefire/Failsafe is 3.0.0. ==== -[[running-tests-build-maven-bom]] +[[maven-bom]] === Aligning dependency versions Unless you're using Spring Boot which defines its own way of managing dependencies, it is -recommended to use the JUnit Platform <> to align the +recommended to use the JUnit Platform xref:appendix.adoc#dependency-metadata-junit-bom[Bill of Materials (BOM)] to align the versions of all JUnit artifacts. [source,xml,indent=0] @@ -242,10 +242,10 @@ versions of all JUnit artifacts. Using the BOM allows you to omit the version when declaring dependencies on all artifacts with the `org.junit.platform`, `org.junit.jupiter`, and `org.junit.vintage` group IDs. -TIP: See <> for details on how to override the version +TIP: See <> for details on how to override the version of JUnit used in your Spring Boot application. -[[running-tests-build-maven-engines-configure]] +[[maven-engines-configure]] === Configuring Test Engines In order to have Maven Surefire or Maven Failsafe run any tests at all, at least one @@ -324,7 +324,7 @@ long as you configure `test` scoped dependencies on JUnit 4 and the JUnit Vintag ---- -[[running-tests-build-maven-filter-test-class-names]] +[[maven-filter-test-class-names]] === Filtering by Test Class Names The Maven Surefire Plugin will scan for test classes whose fully qualified names match @@ -366,11 +366,11 @@ Please see the https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html[Inclusions and Exclusions of Tests] documentation for Maven Surefire for details. -[[running-tests-build-maven-filter-tags]] +[[maven-filter-tags]] === Filtering by Tags -You can filter tests by <> or -<> using the following configuration +You can filter tests by xref:running-tests/tags.adoc[tags] or +xref:running-tests/tags.adoc#expressions[tag expressions] using the following configuration properties. - to include _tags_ or _tag expressions_, use `groups`. @@ -395,10 +395,10 @@ properties. ---- -[[running-tests-build-maven-config-params]] +[[maven-config-params]] === Configuration Parameters -You can set JUnit Platform <> to +You can set JUnit Platform xref:running-tests/configuration-parameters.adoc[configuration parameters] to influence test discovery and execution by declaring the `configurationParameters` property and providing key-value pairs using the Java `Properties` file syntax (as shown below) or via the `junit-platform.properties` file. @@ -427,7 +427,7 @@ below) or via the `junit-platform.properties` file. ---- -[[running-tests-build-ant]] +[[ant]] == Ant Starting with version `1.10.3`, link:https://ant.apache.org/[Ant] has a @@ -504,7 +504,7 @@ For further details on usage and configuration options please refer to the offic documentation for the link:https://ant.apache.org/manual/Tasks/junitlauncher.html[`junitlauncher` task]. -[[running-tests-build-spring-boot]] +[[spring-boot]] == Spring Boot link:https://spring.io/projects/spring-boot[Spring Boot] provides automatic support for @@ -513,7 +513,7 @@ managing the version of JUnit used in your project. In addition, the Jupiter, AssertJ, Mockito, etc. If your build relies on dependency management support from Spring Boot, you should not -import JUnit's <> in your build script since that would +import JUnit's xref:appendix.adoc#dependency-metadata-junit-bom[Bill of Materials (BOM)] in your build script since that would result in duplicate (and potentially conflicting) management of JUnit dependencies. If you need to override the version of a dependency used in your Spring Boot application, diff --git a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc index a8d6ca7e0509..a15cb60ab1f8 100644 --- a/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc +++ b/documentation/modules/ROOT/pages/running-tests/capturing-standard-output-error.adoc @@ -2,8 +2,8 @@ The JUnit Platform provides opt-in support for capturing output printed to `System.out` and `System.err`. To enable it, set the `junit.platform.output.capture.stdout` and/or -`junit.platform.output.capture.stderr` <> to `true`. In addition, you may configure the maximum number of buffered bytes +`junit.platform.output.capture.stderr` xref:running-tests/configuration-parameters.adoc[configuration +parameter] to `true`. In addition, you may configure the maximum number of buffered bytes to be used per executed test or container using `junit.platform.output.capture.maxBuffer`. If enabled, the JUnit Platform captures the corresponding output and publishes it as a @@ -14,5 +14,5 @@ finished. Please note that the captured output will only contain output emitted by the thread that was used to execute a container or test. Any output by other threads will be omitted because particularly when -<> it would be impossible +xref:writing-tests/parallel-execution.adoc[executing tests in parallel] it would be impossible to attribute it to a specific test or container. diff --git a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc index 5e43efa01b84..8688d0e27862 100644 --- a/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc +++ b/documentation/modules/ROOT/pages/running-tests/configuration-parameters.adoc @@ -6,29 +6,29 @@ configuration parameters that are specific to a particular test engine, listener registered extension. For example, the JUnit Jupiter `TestEngine` supports _configuration parameters_ for the following use cases. -- <> -- <> -- <> -- <> +- xref:writing-tests/test-instance-lifecycle.adoc#default[Changing the Default Test Instance Lifecycle] +- xref:extensions/registering-extensions.adoc#registration-automatic-enabling[Enabling Automatic Extension Detection] +- xref:extensions/conditional-test-execution.adoc#deactivation[Deactivating Conditions] +- xref:writing-tests/display-names.adoc#generator-default[Setting the Default Display Name Generator] _Configuration Parameters_ are text-based key-value pairs that can be supplied to test engines running on the JUnit Platform via one of the following mechanisms. 1. The `configurationParameter()` and `configurationParameters()` methods in `LauncherDiscoveryRequestBuilder` which - is used to build a request supplied to the <>. + is used to build a request supplied to the xref:advanced-topics/launcher-api.adoc[Launcher API]. + When running tests via one of the tools provided by the JUnit Platform you can specify configuration parameters as follows: - * <>: use the `--config` command-line + * xref:running-tests/console-launcher.adoc[Console Launcher]: use the `--config` command-line option. - * <>: use the `systemProperty` or + * xref:running-tests/build-support.adoc#gradle-config-params[Gradle]: use the `systemProperty` or `systemProperties` DSL. - * <>: use the + * xref:running-tests/build-support.adoc#maven-config-params[Maven Surefire provider]: use the `configurationParameters` property. 2. The `configurationParametersResources()` method in `LauncherDiscoveryRequestBuilder`. + - When running tests via the <> you can + When running tests via the xref:running-tests/console-launcher.adoc[Console Launcher] you can specify custom configuration files using the `--config-resource` command-line option. 3. JVM system properties. 4. The JUnit Platform default configuration file: a file named `junit-platform.properties` @@ -41,16 +41,16 @@ precedence over those supplied via custom configuration files, system properties default configuration file. Similarly, configuration parameters supplied via system properties take precedence over those supplied via the default configuration file. -[[running-tests-config-params-deactivation-pattern]] +[[pattern]] == Pattern Matching Syntax This section describes the pattern matching syntax that is applied to the _configuration parameters_ used for the following features. -- <> -- <> -- <> -- <> +- xref:extensions/conditional-test-execution.adoc#deactivation[Deactivating Conditions] +- xref:advanced-topics/launcher-api.adoc#listeners-custom-deactivation[Deactivating a TestExecutionListener] +- xref:running-tests/stack-trace-pruning.adoc[] +- xref:extensions/registering-extensions.adoc#registration-automatic-filtering[Filtering Auto-detected Extensions] If the value for the given _configuration parameter_ consists solely of an asterisk (`+++*+++`), the pattern will match against all candidate classes. Otherwise, the value diff --git a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc index 75ae13ce2f7f..1e7da4d9bd48 100644 --- a/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc +++ b/documentation/modules/ROOT/pages/running-tests/console-launcher.adoc @@ -10,7 +10,7 @@ repository under the https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone[junit-platform-console-standalone] directory. It contains the contents of the following artifacts: -include::{standaloneConsoleLauncherShadowedArtifactsFile}[] +include::partial$console-launcher-standalone-shadowed-artifacts.adoc[] [NOTE] ==== @@ -26,7 +26,7 @@ If you need to declare dependencies in your build script on some of the artifact contained in the `junit-platform-console-standalone` artifact, you should declare dependencies only on the JUnit artifacts that are used in your project. To simplify dependency management of JUnit artifacts in your build, you may wish to use the -`junit-jupiter` aggregator artifact or `junit-bom`. See <> for +`junit-jupiter` aggregator artifact or `junit-bom`. See xref:appendix.adoc#dependency-metadata[Dependency Metadata] for details. ==== @@ -72,23 +72,23 @@ all jars in a directory): $ java -cp classes:testlib/* org.junit.platform.console.ConsoleLauncher ---- -[[running-tests-console-launcher-options]] +[[options]] == Subcommands and Options The `{ConsoleLauncher}` provides the following subcommands: ---- -include::{consoleLauncherOptionsFile}[] +include::partial$console-launcher-options.txt[] ---- -[[running-tests-console-launcher-options-discovering-tests]] +[[options-discovering-tests]] === Discovering tests ---- -include::{consoleLauncherDiscoverOptionsFile}[] +include::partial$console-launcher-discover-options.txt[] ---- -[[running-tests-console-launcher-options-executing-tests]] +[[options-executing-tests]] === Executing tests .Exit Code @@ -100,17 +100,17 @@ with a status code of `2`. Unexpected or invalid user input yields a status code of `3`. An exit code of `-1` indicates an unspecified error condition. ---- -include::{consoleLauncherExecuteOptionsFile}[] +include::partial$console-launcher-execute-options.txt[] ---- -[[running-tests-console-launcher-options-listing-test-engines]] +[[options-listing-test-engines]] === Listing test engines ---- -include::{consoleLauncherEnginesOptionsFile}[] +include::partial$console-launcher-engines-options.txt[] ---- -[[running-tests-console-launcher-argument-files]] +[[argument-files]] == Argument Files (@-files) On some platforms you may run into system limitations on the length of a command line when @@ -138,7 +138,7 @@ You can pass a real parameter with an initial `@` character by escaping it with additional `@` symbol. For example, `@@somearg` will become `@somearg` and will not be subject to expansion. -[[running-tests-console-launcher-redirecting-stdout-and-stderr]] +[[redirecting-stdout-and-stderr]] == Redirecting Standard Output/Error to Files You can redirect the `System.out` (stdout) and `System.err` (stderr) output streams to @@ -159,7 +159,7 @@ output streams will be redirected to that file. The default charset is used for writing to the files. ==== -[[running-tests-console-launcher-color-customization]] +[[color-customization]] == Color Customization The colors used in the output of the `{ConsoleLauncher}` can be customized. diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc index b4d06dff4bb9..c2f358be82b4 100644 --- a/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc +++ b/documentation/modules/ROOT/pages/running-tests/discovery-issues.adoc @@ -2,7 +2,7 @@ Test engines may encounter issues during test discovery. For example, the declaration of a test class or method may be invalid. To avoid such issues from going unnoticed, the JUnit -Platform provides a <> to +Platform provides a xref:advanced-topics/engines.adoc#discovery-issues[mechanism for test engines] to report them with different severity levels: INFO:: @@ -22,7 +22,7 @@ _critical_ severity, its tests will not be executed. Instead, the engine will be as failed during execution with a `{DiscoveryIssueException}` listing all critical issues. Non-critical issues will be logged but will not prevent the engine from executing its tests. The `junit.platform.discovery.issue.severity.critical` -<> can be used to set the critical +xref:running-tests/configuration-parameters.adoc[configuration parameter] can be used to set the critical severity level. Currently, the default value is `ERROR` but it may be changed in a future release. diff --git a/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc index 68dc2a0d9a98..5ee75c0d9044 100644 --- a/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc +++ b/documentation/modules/ROOT/pages/running-tests/discovery-selectors.adoc @@ -5,7 +5,7 @@ which tests should be discovered or executed. Discovery selectors can be created programmatically using the factory methods in the `{DiscoverySelectors}` class, specified declaratively via annotations when using the -<>, via options of the <>, or +xref:advanced-topics/junit-platform-suite-engine.adoc[], via options of the xref:running-tests/console-launcher.adoc[], or generically as strings via their identifiers. The following discovery selectors are provided out of the box: diff --git a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc index d3330c3c1038..2cb3d8b551f0 100644 --- a/documentation/modules/ROOT/pages/running-tests/ide-support.adoc +++ b/documentation/modules/ROOT/pages/running-tests/ide-support.adoc @@ -1,6 +1,6 @@ = IDE Support -[[running-tests-ide-intellij-idea]] +[[intellij-idea]] == IntelliJ IDEA IntelliJ IDEA supports running tests on the JUnit Platform since version 2016.2. For more @@ -58,7 +58,7 @@ testRuntimeOnly("org.junit.vintage:junit-vintage-engine") ---- -[[running-tests-ide-eclipse]] +[[eclipse]] == Eclipse Eclipse IDE offers support for the JUnit Platform since the Eclipse Oxygen.1a (4.7.1a) @@ -69,7 +69,7 @@ support for JUnit 5_ section of the https://www.eclipse.org/eclipse/news/4.7.1a/#junit-5-support[Eclipse Project Oxygen.1a (4.7.1a) - New and Noteworthy] documentation. -[[running-tests-ide-netbeans]] +[[netbeans]] == NetBeans NetBeans offers support for JUnit Jupiter and the JUnit Platform since the @@ -79,7 +79,7 @@ For more information consult the JUnit 5 section of the https://netbeans.apache.org/download/nb100/index.html#_junit_5[Apache NetBeans 10.0 release notes]. -[[running-tests-ide-vscode]] +[[vscode]] == Visual Studio Code https://code.visualstudio.com/[Visual Studio Code] supports JUnit Jupiter and the JUnit @@ -93,9 +93,9 @@ For more information consult the _Testing_ section of the https://code.visualstudio.com/docs/languages/java#_testing[Java in Visual Studio Code] documentation. -[[running-tests-ide-other]] +[[other]] == Other IDEs If you are using an editor or IDE other than one of those listed in the previous sections, and it doesn't support running tests on the JUnit Platform, you can use the -<> to run them from the command line. +xref:running-tests/console-launcher.adoc[] to run them from the command line. diff --git a/documentation/modules/ROOT/pages/running-tests/tags.adoc b/documentation/modules/ROOT/pages/running-tests/tags.adoc index 79c807264375..c99cfea4802a 100644 --- a/documentation/modules/ROOT/pages/running-tests/tags.adoc +++ b/documentation/modules/ROOT/pages/running-tests/tags.adoc @@ -3,12 +3,12 @@ Tags are a JUnit Platform concept for marking and filtering tests. The programming model for adding tags to containers and tests is defined by the testing framework. For example, in JUnit Jupiter based tests, the `@Tag` annotation (see -<>) should be used. For JUnit 4 based tests, the +xref:writing-tests/tagging-and-filtering.adoc[]) should be used. For JUnit 4 based tests, the Vintage engine maps `@Category` annotations to tags (see -<>). Other testing frameworks may define their +xref:migrating-from-junit4.adoc#categories-support[Categories Support]). Other testing frameworks may define their own annotation or other means for users to specify tags. -[[running-tests-tag-syntax-rules]] +[[syntax-rules]] == Syntax Rules for Tags Regardless how a tag is specified, the JUnit Platform enforces the following rules: @@ -27,7 +27,7 @@ Regardless how a tag is specified, the JUnit Platform enforces the following rul NOTE: In the above context, "stripped" means that leading and trailing whitespace characters have been removed using `java.lang.String.strip()`. -[[running-tests-tag-expressions]] +[[expressions]] == Tag Expressions Tag expressions are boolean expressions with the operators `!`, `&` and `|`. In addition, diff --git a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc index 8e03a5a22c94..e69ad7165e4b 100644 --- a/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc +++ b/documentation/modules/ROOT/pages/running-tests/using-listeners-and-interceptors.adoc @@ -23,28 +23,28 @@ for you automatically. You can also implement and register your own listeners. For details on registering and configuring listeners, see the following sections of this guide. -* <> -* <> -* <> -* <> -* <> -* <> +* xref:advanced-topics/launcher-api.adoc#launcher-session-listeners-custom[Registering a LauncherSessionListener] +* xref:advanced-topics/launcher-api.adoc#launcher-interceptors-custom[Registering a LauncherInterceptor] +* xref:advanced-topics/launcher-api.adoc#launcher-discovery-listeners-custom[Registering a LauncherDiscoveryListener] +* xref:advanced-topics/launcher-api.adoc#listeners-custom[Registering a TestExecutionListener] +* xref:advanced-topics/launcher-api.adoc#listeners-config[Configuring a TestExecutionListener] +* xref:advanced-topics/launcher-api.adoc#listeners-custom-deactivation[Deactivating a TestExecutionListener] The JUnit Platform provides the following listeners which you may wish to use with your test suite. -<> :: +xref:advanced-topics/junit-platform-reporting.adoc[] :: `{LegacyXmlReportGeneratingListener}` can be used via the - <> or registered manually to generate XML reports + xref:running-tests/console-launcher.adoc[] or registered manually to generate XML reports compatible with the de facto standard for JUnit 4 based test reports. + `{OpenTestReportGeneratingListener}` generates an XML report in the event-based format specified by {OpenTestReporting}. It is auto-registered and can be enabled and -configured via <>. +configured via xref:running-tests/configuration-parameters.adoc[]. + -See <> for details. +See xref:advanced-topics/junit-platform-reporting.adoc[] for details. -<> :: +<> :: `FlightRecordingExecutionListener` and `FlightRecordingDiscoveryListener` that generate Java Flight Recorder events during test discovery and execution. @@ -61,7 +61,7 @@ See <> for details. or executed during the execution of the `TestPlan` and generates a file containing the unique IDs once execution of the `TestPlan` has finished. -[[running-tests-listeners-flight-recorder]] +[[recorder]] == Flight Recorder Support The JUnit Platform provides opt-in support for generating Flight Recorder events. diff --git a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc index 90fd500c730f..33d1c1e9f7a7 100644 --- a/documentation/modules/ROOT/pages/writing-tests/annotations.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/annotations.adoc @@ -12,41 +12,41 @@ operate based on their own dedicated annotations. Such methods are inherited unl are overridden. `*@ParameterizedTest*`:: Denotes that a method is a -<>. Such methods are inherited +xref:writing-tests/parameterized-classes-and-tests.adoc[parameterized test]. Such methods are inherited unless they are overridden. `*@RepeatedTest*`:: Denotes that a method is a test template for a -<>. Such methods are inherited unless they +xref:writing-tests/repeated-tests.adoc[repeated test]. Such methods are inherited unless they are overridden. `*@TestFactory*`:: Denotes that a method is a test factory for -<>. Such methods are inherited unless they are +xref:writing-tests/dynamic-tests.adoc[dynamic tests]. Such methods are inherited unless they are overridden. `*@TestTemplate*`:: Denotes that a method is a -<> designed to be invoked multiple +xref:writing-tests/test-templates.adoc[template for a test case] designed to be invoked multiple times depending on the number of invocation contexts returned by the registered -<>. Such methods are inherited unless they are +xref:extensions/providing-invocation-contexts-for-test-templates.adoc[providers]. Such methods are inherited unless they are overridden. `*@TestClassOrder*`:: Used to configure the -<> for `@Nested` +xref:writing-tests/test-execution-order.adoc#classes[test class execution order] for `@Nested` test classes in the annotated test class. Such annotations are inherited. `*@TestMethodOrder*`:: Used to configure the -<> for the +xref:writing-tests/test-execution-order.adoc#methods[test method execution order] for the annotated test class; similar to JUnit 4's `@FixMethodOrder`. Such annotations are inherited. `*@TestInstance*`:: Used to configure the -<> for the annotated test +xref:writing-tests/test-instance-lifecycle.adoc[test instance lifecycle] for the annotated test class. Such annotations are inherited. -`*@DisplayName*`:: Declares a custom <> for the +`*@DisplayName*`:: Declares a custom xref:writing-tests/display-names.adoc[display name] for the test class or test method. Such annotations are not inherited. `*@DisplayNameGeneration*`:: Declares a custom -<> for the test class. Such +xref:writing-tests/display-names.adoc#generator[display name generator] for the test class. Such annotations are inherited. `*@BeforeEach*`:: Denotes that the annotated method should be executed _before_ *each* @@ -63,68 +63,68 @@ overridden. `@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current top-level or `@Nested` test class; analogous to JUnit 4's `@BeforeClass`. Such methods are inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. +xref:writing-tests/test-instance-lifecycle.adoc[test instance lifecycle] is used. `*@AfterAll*`:: Denotes that the annotated method should be executed _after_ *all* `@Test`, `@RepeatedTest`, `@ParameterizedTest`, and `@TestFactory` methods in the current top-level or `@Nested` test class; analogous to JUnit 4's `@AfterClass`. Such methods are inherited unless they are overridden and must be `static` unless the "per-class" -<> is used. +xref:writing-tests/test-instance-lifecycle.adoc[test instance lifecycle] is used. `*@ParameterizedClass*`:: Denotes that the annotated class is a -<>. Such annotations are +xref:writing-tests/parameterized-classes-and-tests.adoc[parameterized class]. Such annotations are inherited. `*@BeforeParameterizedClassInvocation*`:: Denotes that the annotated method should be executed once _before_ each invocation of a -<>. Such methods are inherited +xref:writing-tests/parameterized-classes-and-tests.adoc[parameterized class]. Such methods are inherited unless they are overridden. `*@AfterParameterizedClassInvocation*`:: Denotes that the annotated method should be executed once _after_ each invocation of a -<>. Such methods are inherited +xref:writing-tests/parameterized-classes-and-tests.adoc[parameterized class]. Such methods are inherited unless they are overridden. `*@ClassTemplate*`:: Denotes that the annotated class is a -<> designed to be executed +xref:writing-tests/class-templates.adoc[template for a test class] designed to be executed multiple times depending on the number of invocation contexts returned by the registered -<>. Such annotations are inherited. +xref:extensions/providing-invocation-contexts-for-class-templates.adoc[providers]. Such annotations are inherited. `*@Nested*`:: Denotes that the annotated class is a non-static -<>. Such annotations are not inherited. +xref:writing-tests/nested-tests.adoc[nested test class]. Such annotations are not inherited. `*@Tag*`:: Used to declare -<>, either at the class or +xref:writing-tests/tagging-and-filtering.adoc[tags for filtering tests], either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4. Such annotations are inherited at the class level but not at the method level. -`*@Disabled*`:: Used to <> a test class or test method; +`*@Disabled*`:: Used to xref:writing-tests/disabling-tests.adoc[disable] a test class or test method; analogous to JUnit 4's `@Ignore`. Such annotations are not inherited. `*@AutoClose*`:: Denotes that the annotated field represents a resource that will be -<> after test +xref:writing-tests/built-in-extensions.adoc#AutoClose[automatically closed] after test execution. Such fields are inherited. `*@Timeout*`:: Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration. Such annotations are inherited. `*@TempDir*`:: Used to supply a -<> via field +xref:writing-tests/built-in-extensions.adoc#TempDirectory[temporary directory] via field injection or parameter injection in a test class constructor, lifecycle method, or test method; located in the `org.junit.jupiter.api.io` package. Such fields are inherited. `*@ExtendWith*`:: Used to -<>. Such +xref:extensions/registering-extensions.adoc#registration-declarative[register extensions declaratively]. Such annotations are inherited. `*@RegisterExtension*`:: Used to -<> via fields. +xref:extensions/registering-extensions.adoc#registration-programmatic[register extensions programmatically] via fields. Such fields are inherited. WARNING: Some annotations may currently be _experimental_. Consult the table in -<> for details. +xref:api-evolution.adoc#experimental-apis[Experimental APIs] for details. -[[writing-tests-meta-annotations]] +[[annotations]] == Meta-Annotations and Composed Annotations JUnit Jupiter annotations can be used as _meta-annotations_. That means that you can @@ -132,7 +132,7 @@ define your own _composed annotation_ that will automatically _inherit_ the sema its meta-annotations. For example, instead of copying and pasting `@Tag("fast")` throughout your code base (see -<>), you can create a custom _composed annotation_ +xref:writing-tests/tagging-and-filtering.adoc[]), you can create a custom _composed annotation_ named `@Fast` as follows. `@Fast` can then be used as a drop-in replacement for `@Tag("fast")`. diff --git a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc index 6166f3597124..71a36ee2c467 100644 --- a/documentation/modules/ROOT/pages/writing-tests/assertions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/assertions.adoc @@ -16,7 +16,7 @@ complex or time-consuming, as it is only evaluated when the assertion fails. include::example$java/example/AssertionsDemo.java[tags=user_guide] ---- -[[writing-tests-assertions-preemptive-timeouts]] +[[preemptive-timeouts]] [WARNING] .Preemptive Timeouts with `assertTimeoutPreemptively()` ==== @@ -38,7 +38,7 @@ Similar side effects may be encountered with other frameworks that rely on `ThreadLocal` storage. ==== -[[writing-tests-assertions-kotlin]] +[[kotlin]] == Kotlin Assertion Support JUnit Jupiter also comes with a few assertion methods that lend themselves well to being @@ -50,7 +50,7 @@ functions in the `org.junit.jupiter.api` package. include::example$kotlin/example/KotlinAssertionsDemo.kt[tags=user_guide] ---- -[[writing-tests-assertions-third-party]] +[[third-party]] == Third-party Assertion Libraries Even though the assertion facilities provided by JUnit Jupiter are sufficient for many diff --git a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc index 67804ac7ed65..3d5fa42d45c5 100644 --- a/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/built-in-extensions.adoc @@ -5,7 +5,7 @@ separate libraries, JUnit Jupiter includes a few user-facing extension implement that are considered so generally useful that users shouldn't have to add another dependency. -[[writing-tests-built-in-extensions-TempDirectory]] +[[TempDirectory]] == The @TempDir Extension The built-in `{TempDirectory}` extension is used to create and clean up a temporary @@ -51,7 +51,7 @@ temporary directory will only be deleted after the test if the test completed su The default cleanup mode is `ALWAYS`. You can use the `junit.jupiter.tempdir.cleanup.mode.default` -<> to override this default. +xref:running-tests/configuration-parameters.adoc[configuration parameter] to override this default. [source,java,indent=0] .A test class with a temporary directory that doesn't get cleaned up @@ -92,7 +92,7 @@ temporary directory. The following example demonstrates how to achieve that. include::example$java/example/TempDirectoryDemo.java[tags=user_guide_factory_jimfs] ---- -`@TempDir` can also be used as a <> to +`@TempDir` can also be used as a xref:writing-tests/annotations.adoc#annotations[meta-annotation] to reduce repetition. The following code listing shows how to create a custom `@JimfsTempDir` annotation that can be used as a drop-in replacement for `@TempDir(factory = JimfsTempDirFactory.class)`. @@ -116,8 +116,7 @@ annotation is declared on might expose additional attributes to configure the fa Such annotations and related attributes can be accessed via the `AnnotatedElementContext` parameter of the `createTempDirectory(...)` method. -You can use the `junit.jupiter.tempdir.factory.default` <> to specify the fully qualified class name of the +You can use the `junit.jupiter.tempdir.factory.default` xref:running-tests/configuration-parameters.adoc[configuration parameter] to specify the fully qualified class name of the `TempDirFactory` you would like to use by default. Just like for factories configured via the `factory` attribute of the `@TempDir` annotation, the supplied class has to implement the `TempDirFactory` interface. The default factory will be used for all `@TempDir` @@ -131,7 +130,7 @@ precedence rules: parameter, if present 3. Otherwise, `org.junit.jupiter.api.io.TempDirFactory$Standard` will be used. -[[writing-tests-built-in-extensions-AutoClose]] +[[AutoClose]] == The @AutoClose Extension The built-in `{AutoCloseExtension}` automatically closes resources associated with fields. @@ -180,7 +179,7 @@ include::example$java/example/AutoCloseDemo.java[tags=user_guide_example] <2> `WebClient` implements `java.lang.AutoCloseable` which defines a `close()` method that will be invoked after each `@Test` method. -[[writing-tests-built-in-extensions-DefaultLocaleAndTimeZone]] +[[DefaultLocaleAndTimeZone]] == The @DefaultLocale and @DefaultTimeZone Extensions The `{DefaultLocale}` and `{DefaultTimeZone}` annotations can be used to change the values @@ -190,7 +189,7 @@ work on the test class level and on the test method level, and are inherited fro higher-level containers. After the annotated element has been executed, the initial default value is restored. -[[writing-tests-built-in-extensions-DefaultLocale]] +[[DefaultLocale]] === @DefaultLocale The default `Locale` can be specified using an @@ -241,7 +240,7 @@ include::example$java/example/DefaultLocaleTimezoneExtensionDemo.java[tag=defaul NOTE: The provider implementation must have a no-args (or the default) constructor. -[[writing-tests-built-in-extensions-DefaultTimeZone]] +[[DefaultTimeZone]] === @DefaultTimeZone The default `TimeZone` is specified according to the @@ -275,7 +274,7 @@ NOTE: The provider implementation must have a no-args (or the default) construct === Thread Safety Since the default locale and time zone are global state, reading and writing them during -<> can lead to unpredictable +xref:writing-tests/parallel-execution.adoc[parallel test execution] can lead to unpredictable results and flaky tests. The `@DefaultLocale` and `@DefaultTimeZone` extensions are prepared for that and tests annotated with them will never execute in parallel (thanks to `{ResourceLock}`) to guarantee correct test results. diff --git a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc index 9159045675f6..b82f9f1e9353 100644 --- a/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/class-templates.adoc @@ -6,7 +6,7 @@ contexts returned by the registered providers. Thus, it must be used in conjunct registered `{ClassTemplateInvocationContextProvider}` extension. Each invocation of a class template behaves like the execution of a regular test class with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. +xref:extensions/providing-invocation-contexts-for-class-templates.adoc[] for usage examples. -NOTE: <> are a built-in +NOTE: xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Classes] are a built-in specialization of class templates. diff --git a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc index ab2d5d500fa1..712c1a06b3ff 100644 --- a/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/conditional-test-execution.adoc @@ -1,10 +1,10 @@ = Conditional Test Execution -The <> extension API in JUnit Jupiter allows +The xref:extensions/conditional-test-execution.adoc[`ExecutionCondition`] extension API in JUnit Jupiter allows developers to either _enable_ or _disable_ a test class or test method based on certain conditions _programmatically_. The simplest example of such a condition is the built-in `{DisabledCondition}` which supports the `{Disabled}` annotation (see -<>). +xref:writing-tests/disabling-tests.adoc[]). In addition to `@Disabled`, JUnit Jupiter also supports several other annotation-based conditions in the `org.junit.jupiter.api.condition` package that allow developers to @@ -21,7 +21,7 @@ APIs. However, that does not prevent the test class from being instantiated, and not prevent the execution of class-level lifecycle callbacks such as `@BeforeAll` methods, `@AfterAll` methods, and corresponding extension APIs. -See <> and the following sections for +See xref:extensions/conditional-test-execution.adoc[`ExecutionCondition`] and the following sections for details. [TIP] @@ -30,7 +30,7 @@ details. Note that any of the _conditional_ annotations listed in the following sections may also be used as a meta-annotation in order to create a custom _composed annotation_. For example, the `@TestOnMac` annotation in the -<> shows how you can +<> shows how you can combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. ==== @@ -52,28 +52,28 @@ conditional annotation may be used in conjunction with other conditional annotat the `org.junit.jupiter.api.condition` package. ==== -[[writing-tests-conditional-execution-os]] +[[os]] == Operating System and Architecture Conditions A container or test may be enabled or disabled on a particular operating system, architecture, or combination of both via the `{EnabledOnOs}` and `{DisabledOnOs}` annotations. -[[writing-tests-conditional-execution-os-demo]] +[[os-demo]] [source,java,indent=0] .Conditional execution based on operating system ---- include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_os] ---- -[[writing-tests-conditional-execution-architectures-demo]] +[[architectures-demo]] [source,java,indent=0] .Conditional execution based on architecture ---- include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_architecture] ---- -[[writing-tests-conditional-execution-jre]] +[[jre]] == Java Runtime Environment Conditions A container or test may be enabled or disabled on particular versions of the Java Runtime @@ -107,7 +107,7 @@ versions. include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_jre_arbitrary_versions] ---- -[[writing-tests-conditional-execution-native]] +[[native]] == Native Image Conditions A container or test may be enabled or disabled within a @@ -122,7 +122,7 @@ Build Tools] project. include::example$java/example/ConditionalTestExecutionDemo.java[tags=user_guide_native] ---- -[[writing-tests-conditional-execution-system-properties]] +[[system-properties]] == System Property Conditions A container or test may be enabled or disabled based on the value of the `named` JVM @@ -143,7 +143,7 @@ class, or test method. Specifically, these annotations will be found if they are present, indirectly present, or meta-present on a given element. ==== -[[writing-tests-conditional-execution-environment-variables]] +[[environment-variables]] == Environment Variable Conditions A container or test may be enabled or disabled based on the value of the `named` @@ -164,10 +164,10 @@ interface, test class, or test method. Specifically, these annotations will be f they are directly present, indirectly present, or meta-present on a given element. ==== -[[writing-tests-conditional-execution-custom]] +[[custom]] == Custom Conditions -As an alternative to implementing an <>, a +As an alternative to implementing an xref:extensions/conditional-test-execution.adoc[`ExecutionCondition`], a container or test may be enabled or disabled based on a _condition method_ configured via the `{EnabledIf}` and `{DisabledIf}` annotations. A condition method must have a `boolean` return type and may accept either no arguments or a single `ExtensionContext` argument. diff --git a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc index 86dc2331fd19..351fe22f151d 100644 --- a/documentation/modules/ROOT/pages/writing-tests/definitions.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/definitions.adoc @@ -15,8 +15,7 @@ any method that is directly annotated or meta-annotated with `@BeforeAll`, `@AfterAll`, `@BeforeEach`, or `@AfterEach`. Test Class:: -any top-level class, `static` member class, or <> that contains at least one _test method_, i.e. a _container_. +any top-level class, `static` member class, or xref:writing-tests/nested-tests.adoc[`@Nested` class] that contains at least one _test method_, i.e. a _container_. Test classes must not be `abstract` and must have a single constructor. Java `record` classes are supported as well. diff --git a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc index 85c0b3d7ecc8..cdb18e0091ea 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dependency-injection-for-constructors-and-methods.adoc @@ -8,7 +8,7 @@ constructors and methods. `{ParameterResolver}` defines the API for test extensions that wish to _dynamically_ resolve parameters at runtime. If a _test class_ constructor, a _test method_, or a -_lifecycle method_ (see <>) accepts a parameter, the parameter +_lifecycle method_ (see xref:writing-tests/definitions.adoc[]) accepts a parameter, the parameter must be resolved at runtime by a registered `ParameterResolver`. There are currently three built-in resolvers that are registered automatically. @@ -36,7 +36,7 @@ include::example$java/example/TestInfoDemo.java[tags=user_guide] information about the current repetition, the total number of repetitions, the number of repetitions that have failed, and the failure threshold for the corresponding `@RepeatedTest`. Note, however, that `RepetitionExtension` is not registered outside the - context of a `@RepeatedTest`. See <>. + context of a `@RepeatedTest`. See xref:writing-tests/repeated-tests.adoc#examples[Repeated Test Examples]. * `{TestReporterParameterResolver}`: if a constructor or method parameter is of type `{TestReporter}`, the `TestReporterParameterResolver` will supply an instance of @@ -55,7 +55,7 @@ include::example$java/example/TestReporterDemo.java[tags=user_guide] ---- NOTE: Other parameter resolvers must be explicitly enabled by registering appropriate -<> via `@ExtendWith`. +xref:extensions/overview.adoc[extensions] via `@ExtendWith`. Check out the `{RandomParametersExtension}` for an example of a custom `{ParameterResolver}`. While not intended to be production-ready, it demonstrates the diff --git a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc index 981acf5d408d..5630bf30eac8 100644 --- a/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/disabling-tests.adoc @@ -2,8 +2,7 @@ Entire test classes or individual test methods may be _disabled_ via the `{Disabled}` annotation, via one of the annotations discussed in -<>, or via a custom <>. +xref:writing-tests/conditional-test-execution.adoc[], or via a custom xref:extensions/conditional-test-execution.adoc[`ExecutionCondition`]. When `@Disabled` is applied at the class level, all test methods within that class are automatically disabled as well. diff --git a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc index de76247ca321..86aef486627d 100644 --- a/documentation/modules/ROOT/pages/writing-tests/display-names.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/display-names.adoc @@ -12,7 +12,7 @@ include::example$java/example/DisplayNameDemo.java[tags=user_guide] [NOTE] ==== Control characters in text-based arguments in display names for parameterized tests are -escaped by default. See <> +escaped by default. See xref:writing-tests/parameterized-classes-and-tests.adoc#tests-display-names-quoted-text[Quoted Text-based Arguments] for details. Any remaining ISO control characters in a display name will be replaced as follows. @@ -35,7 +35,7 @@ Any remaining ISO control characters in a display name will be replaced as follo |=== ==== -[[writing-tests-display-name-generator]] +[[generator]] == Display Name Generators JUnit Jupiter supports custom display name generators that can be configured via the @@ -121,11 +121,11 @@ A year is a leap year ✔ ====== -[[writing-tests-display-name-generator-default]] +[[generator-default]] == Setting the Default Display Name Generator You can use the `junit.jupiter.displayname.generator.default` -<> to specify the fully qualified +xref:running-tests/configuration-parameters.adoc[configuration parameter] to specify the fully qualified class name of the `DisplayNameGenerator` you would like to use by default. Just like for display name generators configured via the `@DisplayNameGeneration` annotation, the supplied class has to implement the `DisplayNameGenerator` interface. The default display @@ -147,7 +147,7 @@ junit.jupiter.displayname.generator.default = \ Similarly, you can specify the fully qualified name of any custom class that implements `DisplayNameGenerator`. -[[writing-tests-display-name-generator-precedence-rules]] +[[generator-precedence-rules]] In summary, the display name for a test class or method is determined according to the following precedence rules: diff --git a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc index 5fea6ae2737f..7878f90d3b2f 100644 --- a/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/dynamic-tests.adoc @@ -1,7 +1,7 @@ = Dynamic Tests The standard `@Test` annotation in JUnit Jupiter described in -<> is very similar to the `@Test` annotation in JUnit 4. Both +xref:writing-tests/annotations.adoc[] is very similar to the `@Test` annotation in JUnit 4. Both describe methods that implement test cases. These test cases are static in the sense that they are fully specified at compile time, and their behavior cannot be changed by anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but @@ -46,7 +46,7 @@ lambda expression for a dynamic test, those fields will not be reset by callback or extensions between the execution of individual dynamic tests generated by the same `@TestFactory` method. -[[writing-tests-dynamic-tests-examples]] +[[examples]] == Dynamic Test Examples The following `DynamicTestsDemo` class demonstrates several examples of test factories @@ -81,7 +81,7 @@ a nested hierarchy of dynamic tests utilizing `DynamicContainer`. include::example$java/example/DynamicTestsDemo.java[tags=user_guide] ---- -[[writing-tests-dynamic-tests-named-support]] +[[named-support]] == Dynamic Tests and Named In some cases, it can be more natural to specify inputs together with a descriptive name @@ -95,7 +95,7 @@ interface along with `Named` via the `NamedExecutable` base class. include::example$java/example/DynamicTestsNamedDemo.java[tags=user_guide] ---- -[[writing-tests-dynamic-tests-uri-test-source]] +[[uri-test-source]] == URI Test Sources for Dynamic Tests The JUnit Platform provides `TestSource`, a representation of the source of a test or @@ -130,11 +130,11 @@ implementations. `UriSource` :: If none of the above `TestSource` implementations are applicable. -[[writing-tests-dynamic-tests-parallel-execution]] +[[parallel-execution]] == Parallel Execution Dynamic tests and containers support -<>. You can configure their +xref:writing-tests/parallel-execution.adoc[parallel execution]. You can configure their `ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)` factory methods as illustrated by the following example. diff --git a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc index d71bea1c10a9..2e1d6501b26a 100644 --- a/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/exception-handling.adoc @@ -5,7 +5,7 @@ built-in mechanisms for managing test failures due to exceptions, the role of ex in implementing assertions and assumptions, and how to specifically assert non-throwing conditions in code. -[[writing-tests-exceptions-uncaught]] +[[uncaught]] == Uncaught Exceptions In JUnit Jupiter, if an exception is thrown from a test method, a lifecycle method, or an @@ -19,7 +19,7 @@ Failed assumptions deviate from this general rule. In contrast to failed assertions, failed assumptions do not result in a test failure; rather, a failed assumption results in a test being aborted. -See <> for further details and examples. +See xref:writing-tests/assumptions.adoc[] for further details and examples. ==== In the following example, the `failsDueToUncaughtException()` method throws an @@ -36,18 +36,18 @@ no effect on the outcome of the test. JUnit Jupiter does not interpret a `throws as an expectation or assertion about what exceptions the test method should throw. A test fails only if an exception is thrown unexpectedly or if an assertion fails. -[[writing-tests-exceptions-failed-assertions]] +[[failed-assertions]] == Failed Assertions Assertions in JUnit Jupiter are implemented using exceptions. The framework provides a set of assertion methods in the `org.junit.jupiter.api.Assertions` class, which throw `AssertionError` when an assertion fails. This mechanism is a core aspect of how JUnit -handles assertion failures as exceptions. See the <> section for +handles assertion failures as exceptions. See the xref:writing-tests/assertions.adoc[] section for further information about JUnit Jupiter's assertion support. NOTE: Third-party assertion libraries may choose to throw an `AssertionError` to signal a failed assertion; however, they may also choose to throw different types of exceptions to -signal failures. See also: <>. +signal failures. See also: xref:writing-tests/assertions.adoc#third-party[Third-party Assertion Libraries]. TIP: JUnit Jupiter itself does not differentiate between failed assertions (`AssertionError`) and other types of exceptions. All uncaught exceptions lead to a test @@ -64,7 +64,7 @@ will mark the test as failed. include::example$java/example/exception/FailedAssertionDemo.java[tags=user_guide] ---- -[[writing-tests-exceptions-expected]] +[[expected]] == Asserting Expected Exceptions JUnit Jupiter offers specialized assertions for testing that specific exceptions are @@ -72,7 +72,7 @@ thrown under expected conditions. The `assertThrows()` and `assertThrowsExactly( assertions are critical tools for validating that your code responds correctly to error conditions by throwing the appropriate exceptions. -[[writing-tests-exceptions-expected-assertThrows]] +[[expected-assertThrows]] === Using `assertThrows()` The `assertThrows()` method is used to verify that a particular type of exception is @@ -86,7 +86,7 @@ thrown exception object to allow performing additional assertions on it. include::example$java/example/exception/ExceptionAssertionDemo.java[tags=user_guide] ---- -[[writing-tests-exceptions-expected-assertThrowsExactly]] +[[expected-assertThrowsExactly]] === Using `assertThrowsExactly()` The `assertThrowsExactly()` method is used when you need to assert that the exception @@ -100,7 +100,7 @@ returns the thrown exception object to allow performing additional assertions on include::example$java/example/exception/ExceptionAssertionExactDemo.java[tags=user_guide] ---- -[[writing-tests-exceptions-not-expected]] +[[not-expected]] == Asserting That no Exception is Expected Although any exception thrown from a test method will cause the test to fail, there are @@ -116,4 +116,4 @@ include::example$java/example/exception/AssertDoesNotThrowExceptionDemo.java[tag NOTE: Third-party assertion libraries often provide similar support. For example, AssertJ has `assertThatNoException().isThrownBy(() -> ...)`. See also: -<>. +xref:writing-tests/assertions.adoc#third-party[Third-party Assertion Libraries]. diff --git a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc index 7f1ac2e85542..ce88abcd2185 100644 --- a/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/nested-tests.adoc @@ -29,11 +29,11 @@ NOTE: _Only non-static nested classes_ (i.e. _inner classes_) can serve as `@Nes classes. Nesting can be arbitrarily deep, and those inner classes are subject to full lifecycle support, including `@BeforeAll` and `@AfterAll` methods on each level. -[[writing-tests-nested-interoperability]] +[[interoperability]] == Interoperability `@Nested` may be combined with -<> in which case the nested test +xref:writing-tests/parameterized-classes-and-tests.adoc[`@ParameterizedClass`] in which case the nested test class is parameterized. The following example illustrates how to combine `@Nested` with `@ParameterizedClass` and diff --git a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc index 5460dfa5df82..60056b77c543 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc @@ -4,7 +4,7 @@ By default, JUnit Jupiter tests are run sequentially in a single thread; however tests in parallel -- for example, to speed up execution -- is available as an opt-in feature. To enable parallel execution, set the `junit.jupiter.execution.parallel.enabled` configuration parameter to `true` -- for example, in `junit-platform.properties` (see -<> for other options). +xref:running-tests/configuration-parameters.adoc[] for other options). Please note that enabling this property is only the first step required to execute tests in parallel. If enabled, test classes and methods will still be executed sequentially by @@ -52,16 +52,16 @@ This allows test classes or methods to opt in or out of concurrent execution reg the globally configured default. When parallel execution is enabled and a default `{ClassOrderer}` is registered (see -<> for details), top-level test classes will +xref:writing-tests/test-execution-order.adoc#classes[Class Order] for details), top-level test classes will initially be sorted accordingly and scheduled in that order. However, they are not guaranteed to be started in exactly that order since the threads they are executed on are not controlled directly by JUnit. All nodes of the test tree that are configured with the `CONCURRENT` execution mode will be executed fully in parallel according to the provided -<> while observing the -declarative <> -mechanism. Please note that <> needs to be enabled +<> while observing the +declarative <> +mechanism. Please note that xref:running-tests/capturing-standard-output-error.adoc[] needs to be enabled separately. In addition, you can configure the default execution mode for top-level classes by setting @@ -137,10 +137,10 @@ If the `junit.jupiter.execution.parallel.mode.classes.default` configuration par not explicitly set, the value for `junit.jupiter.execution.parallel.mode.default` will be used instead. -[[writing-tests-parallel-execution-config]] +[[config]] == Configuration -[[writing-tests-parallel-execution-config-executor-service]] +[[config-executor-service]] === Executor Service If parallel execution is enabled, a thread pool is used behind the scenes to execute tests @@ -162,9 +162,9 @@ API in the JDK. WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. +xref:api-evolution.adoc[promote] this feature. -[[writing-tests-parallel-execution-config-strategies]] +[[config-strategies]] === Strategies Properties such as the desired parallelism and the maximum pool size can be configured @@ -206,11 +206,11 @@ parallelism. If you require such guarantees, it is possible to limit the maximum threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom` strategies. -[[writing-tests-parallel-execution-config-properties]] +[[config-properties]] === Relevant properties The following table lists relevant properties for configuring parallel execution. See -<> for details on how to set such properties. +xref:running-tests/configuration-parameters.adoc[] for details on how to set such properties. ==== General @@ -273,7 +273,7 @@ The following table lists relevant properties for configuring parallel execution Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used for the ```custom``` configuration strategy (no default value). -[[writing-tests-parallel-execution-synchronization]] +[[synchronization]] == Synchronization In addition to controlling the execution mode using the `{Execution}` annotation, JUnit diff --git a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc index 075beac659dc..8f3844fcce9c 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parameterized-classes-and-tests.adoc @@ -5,18 +5,18 @@ arguments. They are declared just like regular `@Test` methods but use the `{ParameterizedTest}` annotation instead. _Parameterized classes_ make it possible to run _all_ tests in a test class, including -<>, multiple times with different arguments. They are declared just +xref:writing-tests/nested-tests.adoc[], multiple times with different arguments. They are declared just like regular test classes and may contain any supported test method type (including `@ParameterizedTest`) but annotated with the `{ParameterizedClass}` annotation. WARNING: _Parameterized classes_ are currently an _experimental_ feature. You're invited to give it a try and provide feedback to the JUnit team so they can improve and eventually -<> this feature. +xref:api-evolution.adoc[promote] this feature. Regardless of whether you are parameterizing a test method or a test class, you must -declare at least one <> that will +declare at least one <> that will provide the arguments for each invocation and then -<> the arguments in the +<> the arguments in the parameterized method or class, respectively. The following example demonstrates a parameterized test that uses the `@ValueSource` @@ -63,24 +63,24 @@ PalindromeTests ✔ └─ reversePalindrome() ✔ .... -[[writing-tests-parameterized-tests-setup]] +[[tests-setup]] == Required Setup In order to use parameterized classes or tests you need to add a dependency on the -`junit-jupiter-params` artifact. Please refer to <> for details. +`junit-jupiter-params` artifact. Please refer to xref:appendix.adoc#dependency-metadata[Dependency Metadata] for details. -[[writing-tests-parameterized-tests-consuming-arguments]] +[[tests-consuming-arguments]] == Consuming Arguments -[[writing-tests-parameterized-tests-consuming-arguments-methods]] +[[tests-consuming-arguments-methods]] === Parameterized Tests Parameterized test methods _consume_ arguments directly from the configured source (see -<>) following a one-to-one correlation between +<>) following a one-to-one correlation between argument source index and method parameter index (see examples in -<>). However, a parameterized test +<>). However, a parameterized test method may also choose to _aggregate_ arguments from the source into a single object -passed to the method (see <>). +passed to the method (see <>). Additional arguments may also be provided by a `ParameterResolver` (e.g., to obtain an instance of `TestInfo`, `TestReporter`, etc.). Specifically, a parameterized test method must declare formal parameters according to the following rules. @@ -95,25 +95,25 @@ parameterized method at the same index in the method's formal parameter list. An _aggregator_ is any parameter of type `{ArgumentsAccessor}` or any parameter annotated with `{AggregateWith}`. -[[writing-tests-parameterized-tests-consuming-arguments-classes]] +[[tests-consuming-arguments-classes]] === Parameterized Classes Parameterized classes _consume_ arguments directly from the configured source (see -<>); either via their unique constructor or via +<>); either via their unique constructor or via field injection. If a `{Parameter}`-annotated field is declared in the parameterized class or one of its superclasses, field injection will be used. Otherwise, constructor injection will be used. -[[writing-tests-parameterized-tests-consuming-arguments-constructor-injection]] +[[tests-consuming-arguments-constructor-injection]] ==== Constructor Injection WARNING: Constructor injection can only be used with the (default) `PER_METHOD` -<> mode. Please use -<> +xref:writing-tests/test-instance-lifecycle.adoc[test instance lifecycle] mode. Please use +<> with the `PER_CLASS` mode instead. For constructor injection, the same rules apply as defined for -<> +<> above. In the following example, two arguments are injected into the constructor of the test class. @@ -130,7 +130,7 @@ of declaring a test class constructor. include::example$java/example/ParameterizedRecordDemo.java[tags=example] ---- -[[writing-tests-parameterized-tests-consuming-arguments-field-injection]] +[[tests-consuming-arguments-field-injection]] ==== Field Injection For field injection, the following rules apply for fields annotated with `@Parameter`. @@ -158,20 +158,20 @@ include::example$java/example/ParameterizedClassDemo.java[tags=field_injection] ---- If field injection is used, no constructor parameters will be resolved with arguments from -the source. Other <> +the source. Other xref:writing-tests/dependency-injection-for-constructors-and-methods.adoc[`ParameterResolver` extensions] may resolve constructor parameters as usual, though. -[[writing-tests-parameterized-tests-consuming-arguments-lifecycle-method]] +[[tests-consuming-arguments-lifecycle-method]] ==== Lifecycle Methods `{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` can also be used to consume arguments if their `injectArguments` attribute is set to `true` (the default). If so, their method signatures must follow the same rules apply as defined for -<> and +<> and additionally use the same parameter types as the _indexed parameters_ of the parameterized test class. Please refer to the Javadoc of `{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` for details and to the -<> section for an +<> section for an example. [NOTE] @@ -189,14 +189,14 @@ method, you must specify the `autoCloseArguments = false` on the `{Parameterized invocations. ==== -[[writing-tests-parameterized-tests-consuming-arguments-other-extensions]] +[[tests-consuming-arguments-other-extensions]] === Other Extensions Other extensions can access the parameters and resolved arguments of a parameterized test or class by retrieving a `{ParameterInfo}` object from the `{ExtensionContext_Store}`. Please refer to the Javadoc of `{ParameterInfo}` for details. -[[writing-tests-parameterized-tests-sources]] +[[tests-sources]] == Sources of Arguments Out of the box, JUnit Jupiter provides quite a few _source_ annotations. Each of the @@ -208,7 +208,7 @@ TIP: All source annotations in this section are applicable to both `{Parameteriz and `{ParameterizedTest}`. For the sake of brevity, the examples in this section will only show how to use them with `{ParameterizedTest}` methods. -[[writing-tests-parameterized-tests-sources-ValueSource]] +[[tests-sources-ValueSource]] === @ValueSource `@ValueSource` is one of the simplest possible sources. It lets you specify a single @@ -236,7 +236,7 @@ the values `1`, `2`, and `3` respectively. include::example$java/example/ParameterizedTestDemo.java[tags=ValueSource_example] ---- -[[writing-tests-parameterized-tests-sources-null-and-empty]] +[[tests-sources-null-and-empty]] === Null and Empty Sources In order to check corner cases and verify proper behavior of our software when it is @@ -259,7 +259,7 @@ for parameterized tests that accept a single argument. If you need to supply multiple varying types of _blank_ strings to a parameterized class or test, you can achieve that using -<> -- for example, +<> -- for example, `@ValueSource(strings = {"{nbsp}", "{nbsp}{nbsp}{nbsp}", "\t", "\n"})`. You can also combine `@NullSource`, `@EmptySource`, and `@ValueSource` to test a wider @@ -283,7 +283,7 @@ NOTE: Both variants of the `nullEmptyAndBlankStrings(String)` parameterized test result in six invocations: 1 for `null`, 1 for the empty string, and 4 for the explicit blank strings supplied via `@ValueSource`. -[[writing-tests-parameterized-tests-sources-EnumSource]] +[[tests-sources-EnumSource]] === @EnumSource `@EnumSource` provides a convenient way to use `Enum` constants. @@ -351,7 +351,7 @@ range of constants while excluding specific values from that range as shown belo include::example$java/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] ---- -[[writing-tests-parameterized-tests-sources-MethodSource]] +[[tests-sources-MethodSource]] === @MethodSource `{MethodSource}` allows you to refer to one or more _factory_ methods of the test class @@ -439,7 +439,7 @@ can be referenced by its fully qualified method name, e.g. include::example$java/example/MethodSourceParameterResolutionDemo.java[tags=parameter_resolution_MethodSource_example] ---- -[[writing-tests-parameterized-tests-sources-FieldSource]] +[[tests-sources-FieldSource]] === @FieldSource `{FieldSource}` allows you to refer to one or more fields of the test class or external @@ -466,7 +466,7 @@ a single argument. [WARNING] ==== In contrast to the supported return types for -<> factory +<> factory methods, the value of a `@FieldSource` field cannot be an instance of `Stream`, `DoubleStream`, `LongStream`, `IntStream`, or `Iterator`, since the values of such types are _consumed_ the first time they are processed. However, if you wish to use one of @@ -560,7 +560,7 @@ _fully qualified field name_ as demonstrated in the following example. include::example$java/example/ExternalFieldSourceDemo.java[tags=external_field_FieldSource_example] ---- -[[writing-tests-parameterized-tests-sources-CsvSource]] +[[tests-sources-CsvSource]] === @CsvSource `@CsvSource` allows you to express argument lists as comma-separated values (i.e., CSV @@ -683,7 +683,7 @@ within quoted strings, you will need to ensure that there is no leading whitespa your text block. ==== -[[writing-tests-parameterized-tests-sources-CsvFileSource]] +[[tests-sources-CsvFileSource]] === @CsvFileSource `@CsvFileSource` lets you use comma-separated value (CSV) files from the classpath or the @@ -750,7 +750,7 @@ Except within a quoted string, leading and trailing whitespace in a CSV column i by default. This behavior can be changed by setting the `ignoreLeadingAndTrailingWhitespace` attribute to `true`. -[[writing-tests-parameterized-tests-sources-ArgumentsSource]] +[[tests-sources-ArgumentsSource]] === @ArgumentsSource `@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note @@ -780,7 +780,7 @@ following example. include::example$java/example/ParameterizedTestDemo.java[tags=ArgumentsProviderWithConstructorInjection_example] ---- -[[writing-tests-parameterized-repeatable-sources]] +[[repeatable-sources]] === Multiple sources using repeatable annotations Repeatable annotations provide a convenient way to specify multiple sources from @@ -808,7 +808,7 @@ The following annotations are repeatable: * `@CsvFileSource` * `@ArgumentsSource` -[[writing-tests-parameterized-tests-argument-count-validation]] +[[tests-argument-count-validation]] == Argument Count Validation By default, when an arguments source provides more arguments than the test method needs, @@ -821,7 +821,7 @@ Then, any additional arguments will cause an error instead. To change this behavior for all tests, set the `junit.jupiter.params.argumentCountValidation` -<> to `strict`. +xref:running-tests/configuration-parameters.adoc[configuration parameter] to `strict`. To change this behavior for a single parameterized class or test method, use the `argumentCountValidation` attribute of the `@ParameterizedClass` or `@ParameterizedTest` annotation: @@ -831,10 +831,10 @@ use the `argumentCountValidation` attribute of the `@ParameterizedClass` or include::example$java/example/ParameterizedTestDemo.java[tags=argument_count_validation] ---- -[[writing-tests-parameterized-tests-argument-conversion]] +[[tests-argument-conversion]] == Argument Conversion -[[writing-tests-parameterized-tests-argument-conversion-widening]] +[[tests-argument-conversion-widening]] === Widening Conversion JUnit Jupiter supports @@ -844,7 +844,7 @@ For example, a parameterized class or test method annotated with `@ValueSource(ints = { 1, 2, 3 })` can be declared to accept not only an argument of type `int` but also an argument of type `long`, `float`, or `double`. -[[writing-tests-parameterized-tests-argument-conversion-implicit]] +[[tests-argument-conversion-implicit]] === Implicit Conversion To support use cases like `@CsvSource`, JUnit Jupiter provides a number of built-in @@ -865,7 +865,7 @@ include::example$java/example/ParameterizedTestDemo.java[tags=implicit_conversio NOTE: Decimal, hexadecimal, and octal `String` literals will be converted to their integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. -[[writing-tests-parameterized-tests-argument-conversion-implicit-table]] +[[tests-argument-conversion-implicit-table]] [cols="10,90"] |=== | Target Type | Example @@ -908,7 +908,7 @@ integral types: `byte`, `short`, `int`, `long`, and their boxed counterparts. | `java.util.UUID` | `"d043e930-7b3b-48e3-bdbe-5a3ccfb833db"` -> `UUID.fromString("d043e930-7b3b-48e3-bdbe-5a3ccfb833db")` |=== -[[writing-tests-parameterized-tests-argument-conversion-implicit-fallback]] +[[tests-argument-conversion-implicit-fallback]] ==== Fallback String-to-Object Conversion In addition to implicit conversion from strings to the target types listed in the above @@ -942,7 +942,7 @@ include::example$java/example/ParameterizedTestDemo.java[tags=implicit_fallback_ include::example$java/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book] ---- -[[writing-tests-parameterized-tests-argument-conversion-explicit]] +[[tests-argument-conversion-explicit]] === Explicit Conversion Instead of relying on implicit argument conversion, you may explicitly specify an @@ -982,7 +982,7 @@ If you wish to implement a custom `ArgumentConverter` that also consumes an anno (like `JavaTimeArgumentConverter`), you have the possibility to extend the `{AnnotationBasedArgumentConverter}` class. -[[writing-tests-parameterized-tests-argument-aggregation]] +[[tests-argument-aggregation]] == Argument Aggregation By default, each _argument_ provided to a `@ParameterizedClass` or `@ParameterizedTest` @@ -993,7 +993,7 @@ signatures, respectively. In such cases, an `{ArgumentsAccessor}` can be used instead of multiple parameters. Using this API, you can access the provided arguments through a single argument passed to your test method. In addition, type conversion is supported as discussed in -<>. +<>. Besides, you can retrieve the current test invocation index with `ArgumentsAccessor.getInvocationIndex()`. @@ -1006,7 +1006,7 @@ include::example$java/example/ParameterizedTestDemo.java[tags=ArgumentsAccessor_ _An instance of `ArgumentsAccessor` is automatically injected into any parameter of type `ArgumentsAccessor`._ -[[writing-tests-parameterized-tests-argument-aggregation-custom]] +[[tests-argument-aggregation-custom]] === Custom Aggregators Apart from direct access to the arguments of a `@ParameterizedClass` or @@ -1047,7 +1047,7 @@ include::example$java/example/ParameterizedTestDemo.java[tags=ArgumentsAggregato ---- -[[writing-tests-parameterized-tests-display-names]] +[[tests-display-names]] == Customizing Display Names By default, the display name of a parameterized class or test invocation contains the @@ -1167,7 +1167,7 @@ Note that `argumentSet(String, Object...)` is a static factory method defined in `org.junit.jupiter.params.provider.Arguments` interface. ==== -[[writing-tests-parameterized-tests-display-names-quoted-text]] +[[tests-display-names-quoted-text]] === Quoted Text-based Arguments As of JUnit Jupiter 6.0, text-based arguments in display names for parameterized tests are @@ -1193,7 +1193,7 @@ in the display name would be `"'\\t'"` which is printed as `'\t'`. For a concrete example, if you run the first `nullEmptyAndBlankStrings(String text)` parameterized test method from the -<> section above, the following +<> section above, the following display names are generated. ---- @@ -1206,7 +1206,7 @@ display names are generated. ---- If you run the first `testWithCsvSource(String fruit, int rank)` parameterized test method -from the <> section above, the +from the <> section above, the following display names are generated. ---- @@ -1227,20 +1227,20 @@ instead of `3.14`. You can see the effect of this with the `rank` values in the example. ==== -[[writing-tests-parameterized-tests-display-names-default-pattern]] +[[tests-display-names-default-pattern]] === Default Display Name Pattern If you'd like to set a default name pattern for all parameterized classes and tests in your project, you can declare the `junit.jupiter.params.displayname.default` configuration parameter in the `junit-platform.properties` file as demonstrated in the following example (see -<> for other options). +xref:running-tests/configuration-parameters.adoc[] for other options). [source,properties,indent=0] ---- junit.jupiter.params.displayname.default = {index} ---- -[[writing-tests-parameterized-tests-display-names-precedence-rules]] +[[tests-display-names-precedence-rules]] === Precedence Rules The display name for a parameterized class or test is determined according to the @@ -1251,15 +1251,15 @@ following precedence rules: 3. `DEFAULT_DISPLAY_NAME` constant defined in `org.junit.jupiter.params.ParameterizedInvocationConstants` -[[writing-tests-parameterized-tests-lifecycle-interop]] +[[tests-lifecycle-interop]] == Lifecycle and Interoperability -[[writing-tests-parameterized-tests-lifecycle-interop-methods]] +[[tests-lifecycle-interop-methods]] === Parameterized Tests Each invocation of a parameterized test has the same lifecycle as a regular `@Test` method. For example, `@BeforeEach` methods will be executed before each invocation. -Similar to <>, invocations will appear one by one in the +Similar to xref:writing-tests/dynamic-tests.adoc[], invocations will appear one by one in the test tree of an IDE. You may at will mix regular `@Test` methods and `@ParameterizedTest` methods within the same test class. @@ -1274,13 +1274,13 @@ lifecycle methods (e.g. `@BeforeEach`) and test class constructors. include::example$java/example/ParameterizedTestDemo.java[tags=ParameterResolver_example] ---- -[[writing-tests-parameterized-tests-lifecycle-interop-classes]] +[[tests-lifecycle-interop-classes]] === Parameterized Classes Each invocation of a parameterized class has the same lifecycle as a regular test class. For example, `@BeforeAll` methods will be executed _once_ before all invocations and `@BeforeEach` methods will be executed before each _test method_ invocation. Similar to -<>, invocations will appear one by one in the test tree of an +xref:writing-tests/dynamic-tests.adoc[], invocations will appear one by one in the test tree of an IDE. You may use `ParameterResolver` extensions with `@ParameterizedClass` constructors. @@ -1292,7 +1292,7 @@ In addition to regular lifecycle methods, parameterized classes may declare `{BeforeParameterizedClassInvocation}` and `{AfterParameterizedClassInvocation}` lifecycle methods that are called once before/after each invocation of the parameterized class. These methods must be `static` unless the parameterized class is configured to use -`@TestInstance(Lifecycle.PER_CLASS)` (see <>). +`@TestInstance(Lifecycle.PER_CLASS)` (see xref:writing-tests/test-instance-lifecycle.adoc[]). These lifecycle methods may optionally declare parameters that are resolved depending on the setting of the `injectArguments` annotation attribute. If it is set to `false`, the diff --git a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc index 90e35cb9f477..d81d9b40dd13 100644 --- a/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/repeated-tests.adoc @@ -35,7 +35,7 @@ repetitions will be invoked regardless of whether any repetitions fail. WARNING: If the repetitions of a `@RepeatedTest` method are executed in parallel, no guarantees can be made regarding the failure threshold. It is therefore recommended that a `@RepeatedTest` method be annotated with `@Execution(SAME_THREAD)` when parallel execution -is configured. See <> for further details. +is configured. See xref:writing-tests/parallel-execution.adoc[] for further details. In addition to specifying the number of repetitions and failure threshold, a custom display name can be configured for each repetition via the `name` attribute of the @@ -62,7 +62,7 @@ repetitions, the number of repetitions that have failed, and the failure thresho developer can choose to have an instance of `{RepetitionInfo}` injected into a `@RepeatedTest`, `@BeforeEach`, or `@AfterEach` method. -[[writing-tests-repeated-tests-examples]] +[[examples]] == Repeated Test Examples The `RepeatedTestsDemo` class at the end of this section demonstrates several examples of diff --git a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc index b38ffbb75bb9..ad5bb6c07300 100644 --- a/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/tagging-and-filtering.adoc @@ -1,8 +1,8 @@ = Tagging and Filtering Test classes and methods can be tagged via the `@Tag` annotation. Those tags can later be -used to filter <>. Please refer to the -<> section for more information about tag support in the JUnit +used to filter xref:running-tests/intro.adoc[test discovery and execution]. Please refer to the +xref:running-tests/tags.adoc[] section for more information about tag support in the JUnit Platform. [source,java,indent=0] @@ -10,5 +10,5 @@ Platform. include::example$java/example/TaggingDemo.java[tags=user_guide] ---- -TIP: See <> for examples demonstrating how to create +TIP: See xref:writing-tests/annotations.adoc#annotations[Meta-Annotations and Composed Annotations] for examples demonstrating how to create custom annotations for tags. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc index aeb1b1d552d0..0dd9e086fc48 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-classes-and-methods.adoc @@ -2,7 +2,7 @@ Test methods and lifecycle methods may be declared locally within the current test class, inherited from superclasses, or inherited from interfaces (see -<>). In addition, test methods and +xref:writing-tests/test-interfaces-and-default-methods.adoc[]). In addition, test methods and lifecycle methods must not be `abstract` and must not return a value (except `@TestFactory` methods which are required to return a value). @@ -33,13 +33,13 @@ a different package than the subclass, that `@Test` method will always be applie subclass since the subclass cannot override a package-private method from a superclass in a different package. -See also: <> +See also: xref:extensions/supported-utilities-in-extensions.adoc#search-semantics[Field and Method Search Semantics] ==== The following test class demonstrates the use of `@Test` methods and all supported lifecycle methods. For further information on runtime semantics, see -<> and -<>. +xref:writing-tests/test-execution-order.adoc[] and +xref:extensions/relative-execution-order-of-user-code-and-extensions.adoc#wrapping-behavior[Wrapping Behavior of Callbacks]. [source,java,indent=0] .A standard Java test class diff --git a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc index 83b38d41fc97..20bae4e323fb 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-execution-order.adoc @@ -5,9 +5,9 @@ deterministic but intentionally nonobvious. This ensures that subsequent runs of suite execute test classes and test methods in the same order, thereby allowing for repeatable builds. -NOTE: See <> for a definition of _test method_ and _test class_. +NOTE: See xref:writing-tests/definitions.adoc[] for a definition of _test method_ and _test class_. -[[writing-tests-test-execution-order-methods]] +[[methods]] == Method Order Although true _unit tests_ typically should not rely on the order in which they are @@ -22,8 +22,8 @@ implementation. You can implement your own custom `MethodOrderer` or use one of following built-in `MethodOrderer` implementations. * `{MethodOrderer_DisplayName}`: sorts test methods _alphanumerically_ based on their - display names (see <>) + display names (see xref:writing-tests/display-names.adoc#generator-precedence-rules[display name + generation precedence rules]) * `{MethodOrderer_MethodName}`: sorts test methods _alphanumerically_ based on their names and formal parameter lists * `{MethodOrderer_OrderAnnotation}`: sorts test methods _numerically_ based on values @@ -36,7 +36,7 @@ it contains, recursively. If you want to avoid that a `@Nested` test class uses `MethodOrderer` as its enclosing class, you can specify `{MethodOrderer_Default}` together with `{TestMethodOrder}`. -NOTE: See also: <> +NOTE: See also: xref:extensions/relative-execution-order-of-user-code-and-extensions.adoc#wrapping-behavior[Wrapping Behavior of Callbacks] The following example demonstrates how to guarantee that test methods are executed in the order specified via the `@Order` annotation. @@ -46,11 +46,10 @@ order specified via the `@Order` annotation. include::example$java/example/OrderedTestsDemo.java[tags=user_guide] ---- -[[writing-tests-test-execution-order-methods-default]] +[[methods-default]] === Setting the Default Method Orderer -You can use the `junit.jupiter.testmethod.order.default` <> to specify the fully qualified class name of the +You can use the `junit.jupiter.testmethod.order.default` xref:running-tests/configuration-parameters.adoc[configuration parameter] to specify the fully qualified class name of the `{MethodOrderer}` you would like to use by default. Just like for the orderer configured via the `{TestMethodOrder}` annotation, the supplied class has to implement the `MethodOrderer` interface. The default orderer will be used for all tests unless the @@ -69,7 +68,7 @@ junit.jupiter.testmethod.order.default = \ Similarly, you can specify the fully qualified name of any custom class that implements `MethodOrderer`. -[[writing-tests-test-execution-order-classes]] +[[classes]] == Class Order Although test classes typically should not rely on the order in which they are executed, @@ -84,8 +83,8 @@ time as outlined in the following scenarios. * Various other use cases To configure test class execution order _globally_ for the entire test suite, use the -`junit.jupiter.testclass.order.default` <> to specify the fully qualified class name of the `{ClassOrderer}` you would +`junit.jupiter.testclass.order.default` xref:running-tests/configuration-parameters.adoc[configuration +parameter] to specify the fully qualified class name of the `{ClassOrderer}` you would like to use. The supplied class must implement the `ClassOrderer` interface. You can implement your own custom `ClassOrderer` or use one of the following built-in @@ -94,8 +93,8 @@ You can implement your own custom `ClassOrderer` or use one of the following bui * `{ClassOrderer_ClassName}`: sorts test classes _alphanumerically_ based on their fully qualified class names * `{ClassOrderer_DisplayName}`: sorts test classes _alphanumerically_ based on their - display names (see <>) + display names (see xref:writing-tests/display-names.adoc#generator-precedence-rules[display name + generation precedence rules]) * `{ClassOrderer_OrderAnnotation}`: sorts test classes _numerically_ based on values specified via the `{Order}` annotation * `{ClassOrderer_Random}`: orders test classes _pseudo-randomly_ and supports diff --git a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc index be2479032530..aa12cdb745b7 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-instance-lifecycle.adoc @@ -3,11 +3,11 @@ In order to allow individual test methods to be executed in isolation and to avoid unexpected side effects due to mutable test instance state, JUnit creates a new instance of each test class before executing each _test method_ (see -<>). This "per-method" test instance lifecycle is the default +xref:writing-tests/definitions.adoc[]). This "per-method" test instance lifecycle is the default behavior in JUnit Jupiter and is analogous to all previous versions of JUnit. NOTE: Please note that the test class will still be instantiated if a given _test method_ -is _disabled_ via a <> (e.g., `@Disabled`, +is _disabled_ via a xref:writing-tests/conditional-test-execution.adoc[condition] (e.g., `@Disabled`, `@DisabledOnOs`, etc.) even when the "per-method" test instance lifecycle mode is active. If you would prefer that JUnit Jupiter execute all test methods on the same test @@ -25,7 +25,7 @@ easier to implement non-static `@BeforeAll` and `@AfterAll` lifecycle methods as `@MethodSource` factory methods by switching to the "per-class" test instance lifecycle mode. -[[writing-tests-test-instance-lifecycle-changing-default]] +[[default]] == Changing the Default Test Instance Lifecycle If a test class or test interface is not annotated with `@TestInstance`, JUnit Jupiter @@ -36,7 +36,7 @@ To change the default test instance lifecycle mode, set the an enum constant defined in `TestInstance.Lifecycle`, ignoring case. This can be supplied as a JVM system property, as a _configuration parameter_ in the `LauncherDiscoveryRequest` that is passed to the `Launcher`, or via the JUnit Platform -configuration file (see <> for details). +configuration file (see xref:running-tests/configuration-parameters.adoc[] for details). For example, to set the default test instance lifecycle mode to `Lifecycle.PER_CLASS`, you can start your JVM with the following system property. diff --git a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc index 81151f883771..d5425fe0767f 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-interfaces-and-default-methods.adoc @@ -5,7 +5,7 @@ JUnit Jupiter allows `@Test`, `@RepeatedTest`, `@ParameterizedTest`, `@TestFacto methods. `@BeforeAll` and `@AfterAll` can either be declared on `static` methods in a test interface or on interface `default` methods _if_ the test interface or test class is annotated with `@TestInstance(Lifecycle.PER_CLASS)` (see -<>). Here are some examples. +xref:writing-tests/test-instance-lifecycle.adoc[]). Here are some examples. [source,java] ---- @@ -19,8 +19,8 @@ include::example$java/example/testinterface/TestInterfaceDynamicTestsDemo.java[t `@ExtendWith` and `@Tag` can be declared on a test interface so that classes that implement the interface automatically inherit its tags and extensions. See -<> for the source code of the -<>. +xref:extensions/test-lifecycle-callbacks.adoc#before-after-execution[Before and After Test Execution Callbacks] for the source code of the +xref:extensions/test-lifecycle-callbacks.adoc#timing-extension[TimingExtension]. [source,java] ---- diff --git a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc index 9afe87e2c9be..c1a9426b6e1f 100644 --- a/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/test-templates.adoc @@ -6,8 +6,8 @@ invocation contexts returned by the registered providers. Thus, it must be used conjunction with a registered `{TestTemplateInvocationContextProvider}` extension. Each invocation of a test template method behaves like the execution of a regular `@Test` method with full support for the same lifecycle callbacks and extensions. Please refer to -<> for usage examples. +xref:extensions/providing-invocation-contexts-for-test-templates.adoc[] for usage examples. -NOTE: <> and -<> are built-in specializations of +NOTE: xref:writing-tests/repeated-tests.adoc[] and +xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Tests] are built-in specializations of test templates. diff --git a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc index 51fb4e18e371..531573c1bc78 100644 --- a/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/timeouts.adoc @@ -26,7 +26,7 @@ within the specified duration but does not verify the execution time of each ind If `@Timeout` is present on a `@TestTemplate` method — for example, a `@RepeatedTest` or `@ParameterizedTest` — each invocation will have the given timeout applied to it. -[[writing-tests-declarative-timeouts-thread-mode]] +[[thread-mode]] == Thread mode The timeout can be applied using one of the following three thread modes: `SAME_THREAD`, @@ -40,17 +40,17 @@ example, `ThreadLocal` transaction management. On the contrary when `SEPARATE_THREAD` is used, like the `assertTimeoutPreemptively()` assertion, the execution of the annotated method proceeds in a separate thread, this -can lead to undesirable side effects, see <>. +can lead to undesirable side effects, see xref:writing-tests/assertions.adoc#preemptive-timeouts[Preemptive Timeouts with `assertTimeoutPreemptively()`]. When `INFERRED` (default) thread mode is used, the thread mode is resolved via the `junit.jupiter.execution.timeout.thread.mode.default` configuration parameter. If the provided configuration parameter is invalid or not present then `SAME_THREAD` is used as fallback. -[[writing-tests-declarative-timeouts-default-timeouts]] +[[default-timeouts]] == Default Timeouts -The following <> can be used to +The following xref:running-tests/configuration-parameters.adoc[configuration parameters] can be used to specify default timeouts for all methods of a certain category unless they or an enclosing test class is annotated with `@Timeout`: @@ -100,7 +100,7 @@ omitted. Specifying no unit is equivalent to using seconds. |=== -[[writing-tests-declarative-timeouts-polling]] +[[polling]] == Using @Timeout for Polling Tests When dealing with asynchronous code, it is common to write tests that poll while waiting @@ -127,25 +127,25 @@ asynchronous tests, consider using a dedicated library such as link:https://github.com/awaitility/awaitility[Awaitility]. -[[writing-tests-declarative-timeouts-debugging]] +[[debugging]] == Debugging Timeouts -Registered <> extensions are called prior to invoking +Registered xref:extensions/pre-interrupt-callback.adoc[] extensions are called prior to invoking `Thread.interrupt()` on the thread that is executing the timed out method. This allows to inspect the application state and output additional information that might be helpful for diagnosing the cause of a timeout. -[[writing-tests-declarative-timeouts-debugging-thread-dump]] +[[debugging-thread-dump]] === Thread Dump on Timeout -JUnit registers a default implementation of the <> +JUnit registers a default implementation of the xref:extensions/pre-interrupt-callback.adoc[] extension point that dumps the stacks of all threads to `System.out` if enabled by setting the `junit.jupiter.execution.timeout.threaddump.enabled` -<> to `true`. +xref:running-tests/configuration-parameters.adoc[configuration parameter] to `true`. -[[writing-tests-declarative-timeouts-mode]] +[[mode]] == Disable @Timeout Globally When stepping through your code in a debug session, a fixed timeout limit may influence diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc index 49435a023433..a4271f992d78 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.0.adoc @@ -1,4 +1,4 @@ -[[release-notes-6.0.0]] +[[v6.0.0]] == 6.0.0 *Date of Release:* September 30, 2025 diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc index 1972f8a9971e..b48b6a74c4f1 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.1.adoc @@ -1,4 +1,4 @@ -[[release-notes-6.0.1]] +[[v6.0.1]] == 6.0.1 *Date of Release:* October 31, 2025 @@ -10,25 +10,25 @@ link:{junit-framework-repo}+/milestone/110?closed=1+[6.0.1] milestone page in th repository on GitHub. -[[release-notes-6.0.1-junit-platform]] +[[v6.0.1-junit-platform]] === JUnit Platform -[[release-notes-6.0.1-junit-platform-bug-fixes]] +[[v6.0.1-junit-platform-bug-fixes]] ==== Bug Fixes * The `jdk.jfr` package is now an optional import when using the `junit-platform-launcher` as an OSGi bundle. -[[release-notes-6.0.1-junit-platform-new-features-and-improvements]] +[[v6.0.1-junit-platform-new-features-and-improvements]] ==== New Features and Improvements * Legacy documentation regarding Java 8 compatibility has been removed from the User Guide. -[[release-notes-6.0.1-junit-jupiter]] +[[v6.0.1-junit-jupiter]] === JUnit Jupiter -[[release-notes-6.0.1-junit-jupiter-bug-fixes]] +[[v6.0.1-junit-jupiter-bug-fixes]] ==== Bug Fixes * A regression introduced in version 6.0.0 caused an exception when using `@CsvSource` or @@ -44,13 +44,13 @@ repository on GitHub. * Fix support for test methods with the same signature as package-private methods declared in super classes in different packages. -[[release-notes-6.0.1-junit-jupiter-deprecations-and-breaking-changes]] +[[v6.0.1-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * The `org.junit.jupiter.migrationsupport` module descriptor has been marked as deprecated for removal. -[[release-notes-6.0.1-junit-jupiter-new-features-and-improvements]] +[[v6.0.1-junit-jupiter-new-features-and-improvements]] ==== New Features and Improvements * The `@CsvSource` and `@CsvFileSource` annotations now allow specifying a custom comment @@ -61,10 +61,10 @@ repository on GitHub. without having to cast class literals to `Class<@Nullable T>`. -[[release-notes-6.0.1-junit-vintage]] +[[v6.0.1-junit-vintage]] === JUnit Vintage -[[release-notes-6.0.1-junit-vintage-new-features-and-improvements]] +[[v6.0.1-junit-vintage-new-features-and-improvements]] ==== New Features and Improvements * Allow disabling the reporting of discovery issues by the JUnit Vintage engine (including diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc index 382420cc04bc..74a9291a1a3f 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.0.2.adoc @@ -1,4 +1,4 @@ -[[release-notes-6.0.2]] +[[v6.0.2]] == 6.0.2 *Date of Release:* ❓ @@ -10,59 +10,59 @@ link:{junit-framework-repo}+/milestone/113?closed=1+[6.0.2] milestone page in th repository on GitHub. -[[release-notes-6.0.2-junit-platform]] +[[v6.0.2-junit-platform]] === JUnit Platform -[[release-notes-6.0.2-junit-platform-bug-fixes]] +[[v6.0.2-junit-platform-bug-fixes]] ==== Bug Fixes * Make `ConsoleLauncher` compatible with JDK 26 by avoiding final field mutations. -[[release-notes-6.0.2-junit-platform-deprecations-and-breaking-changes]] +[[v6.0.2-junit-platform-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.0.2-junit-platform-new-features-and-improvements]] +[[v6.0.2-junit-platform-new-features-and-improvements]] ==== New Features and Improvements * ❓ -[[release-notes-6.0.2-junit-jupiter]] +[[v6.0.2-junit-jupiter]] === JUnit Jupiter -[[release-notes-6.0.2-junit-jupiter-bug-fixes]] +[[v6.0.2-junit-jupiter-bug-fixes]] ==== Bug Fixes * Allow using `@ResourceLock` on classes annotated with `@ClassTemplate` (or `@ParameterizedClass`). -[[release-notes-6.0.2-junit-jupiter-deprecations-and-breaking-changes]] +[[v6.0.2-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.0.2-junit-jupiter-new-features-and-improvements]] +[[v6.0.2-junit-jupiter-new-features-and-improvements]] ==== New Features and Improvements * ❓ -[[release-notes-6.0.2-junit-vintage]] +[[v6.0.2-junit-vintage]] === JUnit Vintage -[[release-notes-6.0.2-junit-vintage-bug-fixes]] +[[v6.0.2-junit-vintage-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-6.0.2-junit-vintage-deprecations-and-breaking-changes]] +[[v6.0.2-junit-vintage-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.0.2-junit-vintage-new-features-and-improvements]] +[[v6.0.2-junit-vintage-new-features-and-improvements]] ==== New Features and Improvements * ❓ diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc index 7f489ef6713d..98a7fd44094c 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M1.adoc @@ -1,4 +1,4 @@ -[[release-notes-6.1.0-M1]] +[[v6.1.0-M1]] == 6.1.0-M1 *Date of Release:* November 17, 2025 @@ -14,17 +14,17 @@ link:{junit-framework-repo}+/milestone/104?closed=1+[6.1.0-M1] milestone page in repository on GitHub. -[[release-notes-6.1.0-M1-junit-platform]] +[[v6.1.0-M1-junit-platform]] === JUnit Platform -[[release-notes-6.1.0-M1-junit-platform-deprecations-and-breaking-changes]] +[[v6.1.0-M1-junit-platform-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * Deprecate constructors for `ForkJoinPoolHierarchicalTestExecutorService` in favor of the new `ParallelHierarchicalTestExecutorServiceFactory` that also supports `WorkerThreadPoolHierarchicalTestExecutorService`. -[[release-notes-6.1.0-M1-junit-platform-new-features-and-improvements]] +[[v6.1.0-M1-junit-platform-new-features-and-improvements]] ==== New Features and Improvements * Support for creating a `ModuleSelector` from a `java.lang.Module` and using @@ -42,15 +42,15 @@ repository on GitHub. `false`. -[[release-notes-6.1.0-M1-junit-jupiter]] +[[v6.1.0-M1-junit-jupiter]] === JUnit Jupiter -[[release-notes-6.1.0-M1-junit-jupiter-new-features-and-improvements]] +[[v6.1.0-M1-junit-jupiter-new-features-and-improvements]] ==== New Features and Improvements * Introduce new module `org.junit.start` for writing and running tests. It simplifies using JUnit in compact source files together with a single `module import` statement. - Find an example at the <<../user-guide/#running-tests-source-launcher, User Guide>>. + Find an example at the xref:running-tests/source-launcher.adoc[User Guide]. * Introduce new `dynamicTest(Consumer)` factory method for dynamic tests. It allows configuring the `ExecutionMode` of the dynamic test in addition to its display name, test source URI, and executable. @@ -65,10 +65,10 @@ repository on GitHub. `junit.jupiter.execution.parallel.config.executor-service` configuration parameter to in order to add support for `WorkerThreadPoolHierarchicalTestExecutorService`. Please refer to the - <<../user-guide/index.adoc#writing-tests-parallel-execution-config-executor-service, User Guide>> + xref:writing-tests/parallel-execution.adoc#config-executor-service[User Guide] for details. -[[release-notes-6.1.0-M1-junit-vintage]] +[[v6.1.0-M1-junit-vintage]] === JUnit Vintage No changes. diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc index 9a9ee9e870cc..f55ef4a580f6 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.1.0-M2.adoc @@ -1,4 +1,4 @@ -[[release-notes-6.1.0-M2]] +[[v6.1.0-M2]] == 6.1.0-M2 *Date of Release:* ❓ @@ -9,59 +9,59 @@ For a complete list of all _closed_ issues and pull requests for this release, c link:{junit-framework-repo}+/milestone/112?closed=1+[6.1.0-M2] milestone page in the JUnit repository on GitHub. -[[release-notes-6.1.0-M2-junit-platform]] +[[v6.1.0-M2-junit-platform]] === JUnit Platform -[[release-notes-6.1.0-M2-junit-platform-bug-fixes]] +[[v6.1.0-M2-junit-platform-bug-fixes]] ==== Bug Fixes * Clarify `TestDescriptor` implementation requirements. -[[release-notes-6.1.0-M2-junit-platform-deprecations-and-breaking-changes]] +[[v6.1.0-M2-junit-platform-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.1.0-M2-junit-platform-new-features-and-improvements]] +[[v6.1.0-M2-junit-platform-new-features-and-improvements]] ==== New Features and Improvements * ❓ -[[release-notes-6.1.0-M2-junit-jupiter]] +[[v6.1.0-M2-junit-jupiter]] === JUnit Jupiter -[[release-notes-6.1.0-M2-junit-jupiter-bug-fixes]] +[[v6.1.0-M2-junit-jupiter-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-6.1.0-M2-junit-jupiter-deprecations-and-breaking-changes]] +[[v6.1.0-M2-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.1.0-M2-junit-jupiter-new-features-and-improvements]] +[[v6.1.0-M2-junit-jupiter-new-features-and-improvements]] ==== New Features and Improvements * `JAVA_27` has been added to the `JRE` enum for use with `JRE`-based execution conditions. * https://www.junit-pioneer.org/[JUnit Pioneer]'s `DefaultLocaleExtension` and `DefaultTimeZoneExtension` are now part of the JUnit Jupiter. Find examples in the - <<../user-guide/index.adoc#writing-tests-built-in-extensions-DefaultLocaleAndTimeZone, User Guide>>. + xref:writing-tests/built-in-extensions.adoc#DefaultLocaleAndTimeZone[User Guide]. -[[release-notes-6.1.0-M2-junit-vintage]] +[[v6.1.0-M2-junit-vintage]] === JUnit Vintage -[[release-notes-6.1.0-M2-junit-vintage-bug-fixes]] +[[v6.1.0-M2-junit-vintage-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-6.1.0-M2-junit-vintage-deprecations-and-breaking-changes]] +[[v6.1.0-M2-junit-vintage-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-6.1.0-M2-junit-vintage-new-features-and-improvements]] +[[v6.1.0-M2-junit-vintage-new-features-and-improvements]] ==== New Features and Improvements * ❓ diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc index 3861188d538e..6bcfc9452fc5 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-TEMPLATE.adoc @@ -13,7 +13,7 @@ // 5) 'include:' this new file in ../../pages/release-notes.adoc. // 6) Delete this entire comment block. // -[[release-notes-VERSION]] +[[vVERSION]] == VERSION *Date of Release:* ❓ @@ -25,58 +25,58 @@ link:{junit-framework-repo}+/milestone/MILESTONE_NUMBER?closed=1+[VERSION] miles repository on GitHub. -[[release-notes-VERSION-junit-platform]] +[[vVERSION-junit-platform]] === JUnit Platform -[[release-notes-VERSION-junit-platform-bug-fixes]] +[[vVERSION-junit-platform-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-VERSION-junit-platform-deprecations-and-breaking-changes]] +[[vVERSION-junit-platform-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-VERSION-junit-platform-new-features-and-improvements]] +[[vVERSION-junit-platform-new-features-and-improvements]] ==== New Features and Improvements * ❓ -[[release-notes-VERSION-junit-jupiter]] +[[vVERSION-junit-jupiter]] === JUnit Jupiter -[[release-notes-VERSION-junit-jupiter-bug-fixes]] +[[vVERSION-junit-jupiter-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-VERSION-junit-jupiter-deprecations-and-breaking-changes]] +[[vVERSION-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-VERSION-junit-jupiter-new-features-and-improvements]] +[[vVERSION-junit-jupiter-new-features-and-improvements]] ==== New Features and Improvements * ❓ -[[release-notes-VERSION-junit-vintage]] +[[vVERSION-junit-vintage]] === JUnit Vintage -[[release-notes-VERSION-junit-vintage-bug-fixes]] +[[vVERSION-junit-vintage-bug-fixes]] ==== Bug Fixes * ❓ -[[release-notes-VERSION-junit-vintage-deprecations-and-breaking-changes]] +[[vVERSION-junit-vintage-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes * ❓ -[[release-notes-VERSION-junit-vintage-new-features-and-improvements]] +[[vVERSION-junit-vintage-new-features-and-improvements]] ==== New Features and Improvements * ❓ From 3e4bbf7f4e10e85fdfe237dbf88e012905640f97 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 7 Dec 2025 17:03:22 +0100 Subject: [PATCH 57/57] Remove obsolete Asciidoctor resources --- .../asciidoc/docinfos/docinfo-footer.html | 33 ---- .../src/docs/asciidoc/docinfos/docinfo.html | 23 --- .../docs/asciidoc/resources/fonts/Symbola.ttf | Bin 2440452 -> 0 bytes .../resources/themes/junit-pdf-theme.yml | 6 - .../asciidoc/resources/themes/rouge_junit.rb | 148 ------------------ .../src/docs/asciidoc/tocbot-3.0.2/styles.css | 1 - .../src/docs/asciidoc/tocbot-3.0.2/tocbot.css | 1 - .../src/docs/asciidoc/tocbot-3.0.2/tocbot.js | 136 ---------------- .../docs/asciidoc/tocbot-3.0.2/tocbot.min.js | 1 - 9 files changed, 349 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/docinfos/docinfo-footer.html delete mode 100644 documentation/src/docs/asciidoc/docinfos/docinfo.html delete mode 100644 documentation/src/docs/asciidoc/resources/fonts/Symbola.ttf delete mode 100644 documentation/src/docs/asciidoc/resources/themes/junit-pdf-theme.yml delete mode 100644 documentation/src/docs/asciidoc/resources/themes/rouge_junit.rb delete mode 100644 documentation/src/docs/asciidoc/tocbot-3.0.2/styles.css delete mode 100644 documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.css delete mode 100644 documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.js delete mode 100644 documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.min.js diff --git a/documentation/src/docs/asciidoc/docinfos/docinfo-footer.html b/documentation/src/docs/asciidoc/docinfos/docinfo-footer.html deleted file mode 100644 index 221366510a23..000000000000 --- a/documentation/src/docs/asciidoc/docinfos/docinfo-footer.html +++ /dev/null @@ -1,33 +0,0 @@ - - diff --git a/documentation/src/docs/asciidoc/docinfos/docinfo.html b/documentation/src/docs/asciidoc/docinfos/docinfo.html deleted file mode 100644 index 15ca19338a7e..000000000000 --- a/documentation/src/docs/asciidoc/docinfos/docinfo.html +++ /dev/null @@ -1,23 +0,0 @@ - - diff --git a/documentation/src/docs/asciidoc/resources/fonts/Symbola.ttf b/documentation/src/docs/asciidoc/resources/fonts/Symbola.ttf deleted file mode 100644 index 055f02558b9a1edd0036bb1f48f435b250d474bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2440452 zcmeF44Sbj5{`f!l`XPR;`+()=DzT)M6zy6_&yfk`R(fhY*rQ z=nz7j5JEa3gdt8CI!*|y@BjU|zW2S>6wdFQ|L^~M`0w?4?{hsr-`92B*L_{rS1b`Z zNJ_<#+=1Es2V8OEvU{a<#}pCE9+*3H_=`{7@>glyVHU2I4IF+_-xnk9XVUt}B9TKI z3?1GvJ+sj#@8EV6_66h4Iiq-j*L{JsPD>T3``%fTW}G?T>o+=!l{rFM_G?!({*1z= zv!7dv+pUmUghAtbx^BUL1N13H=S(lzJ>v7v(61I*G%({DTY*%PJJMP*|BX`^V~5|2H1Zqg;k zpI*P$_aadYMBZL_|E{>4KmVseyR#eZh>#yi5Zm}5c#%la?rf39^3$LyX|y9SS5M}z z%}r|3=B9e%t$Sppc%gY99YS)w4c2@i-TpD&#RPd!T-yC4*V<`$w(U876ya8g9qTKx zSbbMoc%@5<22344Ua}-PwmY7NNRhp!K&(4HqMV)EyuQSdEWYPTsm5l9ESK%}o03I@ zM>*?cl7F$J``zVqyRl5Nm&>Uz3G=CbS6PmqIgVf_a+BSik`p-|?uP;x3h9A57pY;Y z*-*QsELAj&5a(Js+1nv`-Ui7gZP{K|coYUnw)-P;Ev%PpyF#*^S5SY8Ic5<#?sO6?*uVz}djw1!etfAyM z4W*a$GkGbH4E$=?H`%$kX(*RCZH@n@{U_y;fL^BTwcPhZqy^?$7t}*dv>pNuMz%F| zMOmAA(7LFB-_@#T^lD!NQx_jlAFC-BE%*K4y+c`17p5MxE&@zFXkDbo9*2#TL3gbm zQx94fHPCV~dbO_!bz$lZsd?AW-?uz|SFg{zK69pxQNQ7Hug{)7|23s^vt-f^8hby{hgFfUIkJ^Lr~|S+^*-8f zkJ$#&Kpp!Naq|m$>e{(eGR!lfWubl2->^%NWWQs)pYh+u4RKL7y~BE-{Oh`BNax7$ z`Ygm|n>yBKWffuY97KkrUQ1jr5*BIY`8Iu-mYHdTKhk^0%cogbPJRx4+K|WhkV_@g zpN!wi8u`4+q&M4HCB0yzYtuhx6YkZd?>*c#rv2nu;{0HVyHJ+c^g{`&=`(+zf89*D z+HYv+ z2-+X@p!pi9ZM|liLw}Li@HYv6VVZ*Ys^ba53G-4dYdy#0u>*Nr8-LDX+iItyRy*Gt zUl4ED&cpWY&LZ6x*GSj3)E&=_i+ksB=@GWkU!^BZ?*U}k-kk)(E~I`(Q@50jPy6*> zz>NHdeVIP@COtY<-3ZgA6?K0EZNE3=)!Q3`eY_kRh5d;?8nYt_XPb27`A!bwGkrJD zggzJg{FpwQHe&k3_Jkeu+ulIb)1J>|Fv*7Y74d##$|98YV8loWuA8d>gM>pT2dA3 zwb*?7B1u&ofs5sEcLj1Pc55X|=XTcZH8>76XuT`$D&`H!DRG=5m^Xm@4L5sm`*Iwk z-?3M3orqcq!m~a=9bn_m-i&@QybT)(GZnMPU^?my(Dc1Xx+jy?xkyb)I5aM+0BWR3)x>GAA18mZn|FcT$BI97v-pena$IXPl-K1;xh1h9%9SwuyRGp8+e=Gyp3;So0 zhapP?u0<*}^t&74rVCsJM_{)H*%fHgs;(j)t%u!OR!se>cDt9-Zw_NT-p=?oRyr~N z9R>sZ)9L@mNrvpAu6Yhac%NCKeVX+M?L_C+^oz8cn|yK?$z=Q-!W-8;s1uO0c~7X6 zdZzE>-NdEebRUWLjoMG^*rMZsU4dkr(tfl0y~K{&88`J&>s~ZGv_e#3XJ4_$i4|Ci&n*(>#(H{!T``rlU%iwd=lkxK* zYQ}r_IMmDNXEn@+Fg(oOZYg z#v=D3Y3%NhuKK>_EGC@mB;V;M1H9*P&vWm8!n`3#dOBZXUm`u-Lt@jN+hSKb$CCH= zrKeXyxo?Iyao-nxA@X_L5r?Kp>(0z+i7%{2Hv=_!({hcrrW}94-G`EhezYlTm5gBu z^_Zu1r{+2yYkfgmZ3oegCs8Fb8~-WB!lw~M`};ptq+T^_i_ zz43QQjk+hDwd>u48P+>t`+W%K+&Dh%C_-78xQILQIO=W0q3=b_q_r787%SW-V$bP# z>MvwGxdr`40aqdKWh}`@2IHTR%pN{Wx?p~J8%ohz_M@jd-!i;f> zhpMypDN@J8VC?3-qM?peYUeQi#NWYUFPizqv4qh8JKj|o$Kz?zv5`2KKNfqh%Uu6_ z%Kz_jY-Bt6j$p3&Ybl)*x{+5GJ$30mE1jd1gTIn67D-=cF6$40dDzah%uKoinZP@L zg#7rFm6uI83z7BE2k~lsn>0@p9`P#r)T&AJ8-AQB%zmO@{%MlwD=14-&y<0#CpcOL z)VaxbEvfadb)aoP>p|;Z^Ilso_|AD{u{{4q_6iB^%0?cZIyKGH~cP?*JntNbPh=w|5gvtd_&m^KFS{7W z8E18#Qk75J*0EaEZ7^rfv8NSg6VX2f=U}!;K&VpNyM1NW&E5EMR=lH7LrpjYFRu z=}F&yA^HZmKMFg_f_J`Np1w~t#r)6G%72XKhj&c-z1UBYD>2Ui?0LUx={$v+9+rCS z;$`B$Ir1b}0TJ}fW!&p|_ggGyvCh%OIR##kv*=^a@_0{jUXZi2T(yi$IUOp;nDU&6 z9v?Ize7=o&_wjJkHTDbdIc>b2L76X(&3EhKPxD9F)5gtvhW!Qe zIxY9>B*7UWnZ|x0<*a2&89NJ+Z^C=b5xpq??WS+HK(7P(R9v97Kk)si}9*wt&I zu~=MREg#o$P}de}%im4MfyTDbT*o9W$51kN(X|Pk@9jq(>X2@oa~(idud9aZO9zxX z-v5E}V{#N9djlDcX}>4Un9E!&l;PY(-;+!~Q(KZ2)-jW-*HV~g=z45GBkvUa={jqz zImo{H*kAV56aR0z-;e$8v_qZmJNFRJ0o>8v%=&vMy|AA5D`OuY(0&!=zMAy?o~%`m z)oZ{x%>8sN_&`$M-RR@PdZ{fVyt^_!H*zRHdk^m7bFT)b&(?nX08rlg4xQ!m1=Mc` zSpljC^S&Ca`_)wY`aZdo_iTEqNE$E~QuMv{w}>>xT}${99^{K`kAP7~(D&vzv8~9) z`|4v`UE-oY5!N8ZeGy4-X(&d5dEeA`&RY2N)IKXDkw@VIU_?;N`?S7OAAktGdE{x* zb`bI>;?Q^N-@u)M^WkuE9WcozOREKVaGh?Zao})wL)^*QNGX zMyCDUgWJ1+HlpiB>Q?hd(j^L^v>zZm^wvpnGowZ?rTXvJe@q@uSMaaj>yrp8$rqW= zcjKiRCTnKbz`fQdQmWEfXSL@0a$n|erAEHZTp5@vr4d&jd%0|5-nWf#wxOT=>lpW% zunj^I+DLkx*Cm~GyQa>W($sxjn$}d?o8)l&HR%XXdr{UB&gXkM`vx>^&U$HVSS^P~ zM#u`{yGpLx6Cn-7FvVXXC$si+vOf?%I)_~+Dc(c!q2jzRli81O9dpl@Rn0zx)h^%U zohs>JFTiaQ@7tNAX%BJU73^K;VAR?8GkY1Vm-go6Kcb?HyPEfeh7v`6JoJLo0@=%b zPD(@U!=yh9(>XBqUEvZi-~Ew)+&}Lx`mSQ;#B&3+hB+a=7H{4|R6hed*5!4s?2V4E zwV8MHA8GgORnYm7J}(K)nJY1WF>{1WS*Y_szeJALIhW2y_y&;b4(B~$EqX=Anj4Ue zG2RJ`EyH;>R>}bVHt80~$Ova72&Rz#X9F?j{13=-MpbHzkC`Hm{+w&pA)C5 zEpj{Wxo5-cKrgCj7(b`Ljja3VdNOi%d#kN^e^x&`uzMvg!}vnEyBFV+QoUQ@9LZ!Y zYb@(+{k)$^>r3SCE2+mfqGpT_W1Y&_CciAU#v3Bt{dweXu3TrhGxm!6g*5V>;9Jq@ zauR*dQNGI@^DaqZ&94`8r+oKu%JePFQY6QFL|XWDDa&4zla}wrl2M1}EMXq+!-CmB z+NjPYA0r*gkl1(hO=j&@`$PXlX+?Zzx=X18O2b_x4|`Y2be&r#OqIL&z9Zh%l=Dc| zYac@%j9et+BV(m!ou>%rS}FDB%e(GQ(!lp8?+mzIE^){5-CQ}FHQvi&4|@Hj%)Ld* z_~umN*s&>oPr1k2DyMj_%IVRD^nG8kW?aB}UaL)3{)mEXF8}JYMuLh6PJm1(UzV=uWbzbh)o%Ero5`i!wckx zJpyhik~N7a@5%{(MLhvC-kDWK(|O0`{ebss^DR@`di3siSVj`A+UdN|n@&H$x>|y+ z9X~0@(JvLiQ2M`V$QHF^OZ2m9F-_gnq_)4%E-)XCY^j9ifgGGjI12h%*q>jUz+GqL z;6Oc%K5mc_>RqvP!(6NV>HTH#{HR^14rSneI`N;0db;9%D#r%0x0<8xh5k45PuwjO z+|@3>%P>=>xu2MDj8yghz}*#oYq?UvzNh;0m+wu#>Os>PmVHh2G}e)HOud=x3lOG3XU9@<`{iOdM|!}EQW;?$EgYpbO3o@DkMvcIqWUiPNXZ$RFa zpbWxrR8mL9p?RJ9vRn!E|AeeA3;d{hpD=X(N&c$w$L{|*B|YZ3t!=N*vtP%AIW1bs zUf9u=>;6^d1)PpNow?KV&b3w{^Uz~LN!~Pn)lfFgS%3V{ZzDqju6Jiiebz@?yR)SY z)KfS9XgPy%q_C!6RePNnpOwqv;OoFSp-L^gBFZ)1KkfB1i1yZmb?31)+|vKW zVygcwJM5R^FCW?5s5S28a=H40L4lm6VN)JVm6*q4uI&h^bskC$XROzOZwD_x{8=%1 z3frE}i}W2#->n!6(s_SQ#Vj?@XZVRy66q_~5M~p~X@Wgfj#j_qcexT-52aG*r%56D z0sb!ZFPSuGI+YXrZuI$GrPSYyyLj3(eIZvx5>4A@KQ?)+zzsw*;*d8TYyK^0n~6&7 z0m2)o9F)WseV~0*LwmcCw5|8MdQEG`Yxj{th3^J~YLJ0CxZOIA=%~X2prKu_78tJQW zNF^@>Hx(hg1K#BqTf5>Iceu6GJ!Y~Ccgqx~o7F9Hm25_R7$pB!h4%U(dnWe5AH#E= z3fa8h{vaPl=zEy!e@Gry{hL`rc>hN1#Zj^Eg4^M6xE4mkQn&=JiHda`d<=PjoizfO zXBv3}Qq4y~$A53yelwr{?sEO_6y6ld`H!G^lK;$g~ z{XvQq_WBt#KEj}{rp-(;b0;0U#qY~I1US!1E^FC^n%~Hc(oJEGJb^L4eYCAKFw_`_ z`S$aP2`33Z&8Sz1bTZ*Lj$AD(_F|XD)pn`3iM6fN>UW;gh(Fm~&pdIL6fpNFREgOK zkp@zZZ0!F`xMkAYe}*+WU`)yWZDd4bgyeoJf>9AHh23TJ}(U zE$NY4NW)=Ln9xU7M5mDU$B|DW=RgVEfW9+wGV(>ZQdaoAk^g*uIu$>;a77^Z)n_mt zPA5&g7czG+I5)^bC)<$gJ;OUidsBW5@Nd2k{D$m;U5)O3m8P>G*kwdOHM}#NMV{e*m0D zUHrs%jtTHF>T)FE`rjir@$7-~JZ&DgksXqo@CmXH{lSs6YutG$@(OKch4;K{VZNX5 z{2;^ev%-IvHZ~$)j;tq6UB6O}hZ^OfYAZBL#BQwGhiw^k3HGld`@`ih3Q|GKwGg{{ zaVc|L(9QgsyNt=$hh-pk=OWNGHIigj87&b)+!z6>%a}@Bbp>uuE4W3;0&>4D~i1 zcpltGY4ZbRP~?_nc+3hIYGDsmf=@O+KGD_jqA=sVWYhfPLZ09T1<-XpY$$anBF?Pg@0 z$e++F)L-O*IP9w_j2w?&+NKgojbrMEI*MpHuV#!HDR8FTgEBTcb|iy(BH~C_f|QHZ>NI4d67l9KTQ%1!J390d?U3NalU&I z=eu8&Q(+R{0hcQF0L%xl{>8a4#g$k$>b+^5wKA<1)6pwu2Ij*9y~^`+e?LsB!9>(G zuybqJsk<6>s-`sc_l0vdW6jyscZ=xwW5%HBF)19ILK(N$^>wqB9LjL4vKGm8_VeuJ;d_{lw~DH( zSuZD5s{`{$1@kPZZO%M0A5N~8-Kf7>ME^uOYMK2?U+Wz{dL!@CfV-mFM87mKXQ_tMFS$ChP3)auy3&O?SD3y)_H=#wpFs z8bpvU+9cnA4ULdWFGa&Qcc^fp%Dqq)*neV=7%&%Jz&v9CZYDu)SVy?m_XmR?d`k=^ z>-y7_=m_g2_WZQ+T1u7>m? zuhVbC)?)Ihb@oTmI>)V54^9dsYQFuL^07w7Wp&%AQFpQxyR8~GYXXJA+-;xl_4_kR zDCRpJVAn0cd@~Nz`}pS_cbefgS>oTu-Zh;cUKtRdEAHc-Z<^J5&e%U?h6PH4W*a~anCZ^-bwSm^IS`r789``?qHzfc$RxWx0v#&ZT4&ZxrA2@Wn;bBhu2W=lUB~M?yIkr7uJ@hD+luL-@?8Oo=-*hTezih$jcK7{xn^6U|9(JSC@0H zbh$qx4tw{OEB;QxN|J>&rN7gTa)-pin$)xp-K*KJ%nLB9$$rC+`wRX5O8x`;AEZ2z zEalZQh%0m(S;6;SFnZiaDGTyCjkTD#*@0xOaM(YwuqI*np=8WkSd-8^l+iB4T?4-< z`swksYx)&k^XA)Ynzpq_4_Ox(M0?ZpK^S-Snm*~{`80X(=8(rGjPuDd-sKJ+_9^B$ zPqLOANY;uw+x<9$8I#s}X2{#dzD7MObEzEUvG>-T>0zI(o^fK0#+x z_%3ssARNw3W;>1WSBbn3c{8#-l6!odHl(iwavAb)c9&;_1E$9bIk1)Tc>~6+9hdjQ7qzpK7+cPqWwBpx06!|8y zrSxQfGp7@F+lo7faBS>8<-9G)j;*P_<*iG)$b>`Tug znsbQk9Iif(sP+eAw;SGpe*pWctHxq}5V8|ME5>nN z|Ia)>pYpxsVDvpW1I;tc9?8yr2J$({NPM0$ABw&Y`j@ePIrf=5CAKm0XzV@znAmfy zFK4qCw{w)f$^R?%wax-2kiJMG`sCXrn>IU$vj`V+=74AKry{3Z3V2SEG5-d6D!8b( z0w>S(*)-1!XBu|*Fn23)2a?`PV$Sdf`A%#{_z#m0?wZqm>;CuLTawHD0=gIeO1|@* zLAp89&Yr|<=2@LNqtOrjG3*!0_QqoW3g(>8jM7K>G0qzV=?(MY{J?qhBcu&!*#;}< zbF|;dcIt9&rkSMEmkhKokxWzWoPY2c8@#!c^;x(%oqCBO8#4Z^K`!N)*a(S~*J9%1 z{CSkSA${sEN*~YqLl?bUkiA}eWk2-n*Vn!Mj_$$#mNj$s^XV86ob`?C>GSxWq4yj% zU<^IVr?2Mr*$mE7WxLy{chbc>qMpS~rGHHIZO&j^PCVqre+cv7UI)&GWqW%5VLbj0 zB0p!N=Zw6LuX?63JR3{f%C>1Y?g#PkswHtbyE#ul{&;Wh;+!9wV!y@tkZjU77V{;< zt?jcNVZBSZoS$)SLsCY1kDL1S7{8q#xmWC6BWTWMOtalX*e9uH9?<*T&*Kf!@ME(b zJ&VnA;vS65L~?G0vnkmw_kOTnGTVI(IS%;)l6L35K{=OdTDhb1E0gvv{w0j1cN69$ z?7!#U#V*Lvv_I<2oLhbonFXBvb;l7-_?&8c)O#7epqy0xh@1Mog7w_-50lmL~_vX&_ z2PT{@?h%+z#Lp9q)2o>i-9&yUCk@LyXFO}}FHj21xm0>d$ZfF{FKN$5?gz2y?j59~ zg1X>72%CKrb}Mlm&SFuPojF_7*>6l(_v42);HF3?z8iFLuLJz~v?Ko~!tBGd^_ei9 z{;Pjg?c!&hs>a3TZpL9f1N94i&u`j26L+^ae#W9?$g^^#*xJNcITeZ8p2hgJY_C)` z`xXtVW*>Dm-sg<7wTS9_+@yGTq13Qz!h2n@{dzpiP=;}Yk~=d0kQ<)$V*4A?@h8G7 zgJWR<`Z>r{DNZ17&I19fF`I{-&NXUtYhboEkQ?{9VGgmc`xalNL+o zFH7QayEEecc)p8W^5X%0Q8D9EailzMr|Dq6UhJO}hqGnHOuCAh8x}|V1#UD=%&{UP zaT}!HWzOWCjM@E|F<+uDDE1bk9s^qg?mz}OkDy*f9G#Gqkxw1be-<;>F7{qUj)pTS zrw1v|naG{E+X0USoR4gQThiv9h-?DeNaI}eq)**Bmc=~h#oTLH zOy5!Lo`j?>+=p=6mw3L2hrzpiG5vcn{Xwxa6fQ(P5(Z%YEOG-f4fi*iwSZ#IxfR=Q zW3FNK1}#^0_Z8)#dC;=Z_==$y`rFWxR)_Gty2v${C*eo+#Oo9g-g(qryI5mq8guT8 zIeT=U^t89cPOy1r@Qy*P?+&AZcO#yWo}Rul@P4Fjo##N`9k#~x?nKnz@s7|1`C@#& z&pTjG-V1s<7X*HmqwdcA3E&;ZU9ht`qqq!p0kQ>hkz^)337sU9eQ24Cx0$RfXL?iN zE8N#d;?FI|+{fKC)P>EGV2gmbO_uQH;8&Krw~#|IdpZtvnaO=o znRRf-8O2PW@{ay3?mzKa)RcXl_u|xjinQDmcdPCb$WP(`ApeIp#}8$pB#g$*^Q5(F zJg&$X%)!S!bKgvdyKK0RDl>sHX3tq>ggUk6;r>hPPr!`2b@A(O2>69`jEk#z2hH^I z0w~`|9n^u0(1z6B`5TQ5HQeeBJM1|HS;tC%hl{4kXe(pds=i7_C^-IX9;JUq|5%oI=)HXGpTw zNRIOkVz1E!gb|V=XV@vy@>gW=uACwHFa{kPE%eD<2PRIIas?}OYi*A`|1EpJZ|bBdO%aUJ9wj;w_5A({IdlI22Z z=Pakb`F#m{FvROr>opE%;F*6_BMT+{SA37ZWD}-_TayWaeu6cTJ0r&OE&L)GrZR+e zo?(WwWSIAf4D(mXFwP_mW8dMhXdmn_H|s)88N+pc!#szy7Tf1TNdWT$#?WHkCyF_5 zp6h+Y-qBy;Qq@L38ncVxX7t5@*-h*vO+Y;;&>zkEO{2IQ_0Ra4>rF=LUet=f-7ToG z^B+X2J-@RO##u8iU-z>TS4g#;k9*RjVVZC+it8ztxH(}m_UE!LYxKt7kQ(YBKkNn0 zRT%4Y-E{%I_o{hc=orFX0IW^@?_QJof1Q6P$I5nhSlri7J!Dzg3ETIrkA!8G-iy$a zd2LTm*WsCOG8ga3+`6a7T-B>&K6yBL3-w1x=9v-JrPZ9dbWe8=avW6Q?mc8z*aUxL zuA7K_190Q!!6DM#ohj{|^8)z<>a$TF4l5ZmPKM`V6M1iGZ;zAqyh|JN(4X;pF@7BE zw+D6u_>G1SQICNWvBMwh3jMr#aD%+%UBa4HCA@+Ddh~PXqaUI_ze}cj_hUYuGqg`* zhdJL6-g39arMD2fCUUGd%S!R?u%>ulvR~S@E@%C!pC7R=_$1^T(4!j0(fNB|rr%cy9M9ao%=uK_A-4 zfy?ZVVox}`!o4JKGH$#XIZaAPQwiS?%G`Rf@7zJgPYK^=PIMMo zp66rNO-lT>$S&Nsxr{qOKGyFrvFE+r)=~bWR(~T3<#_>EH?Y5Isy$VTkFXWtQ2lP*i&toJ z_hlaIH%HTVxAz{Gu3mR(=RP9?BY&5Hw4dhQdE_mdbIk9`)3k%@JYYY}H;MJ~ zEzi~iUJH4KcKI23`pkL55^o4=o`>_z{BZ7^_=2<8L*#nYfHu?| z^E}9bTzDD#JSadt1~;8>+Z}hUS+Bhu+S~7P57bgAqTb7R*X?4|OQn-tkNGS(uSj2{ zhS|}LN^|V5LSBKq6u&L-cMkqqW7Y|?u7sVBSx@u>upeyJ;99WOrR%PXIBUgvE3%8D z-!S!e5yqp>VXc;XM0p;}ZzIqzb@5rF92S`Z?~MYU=Z?z#k<|DZjyd2WUzjn|cq#R`}USkMkB2V>|pUv^&0~^88BV zO-R7sDDwXgiFoT`f5pCOf{pvlu`da?sh1U-;bzHbp3fBCd-566vz$BRG<%yg`crrICgcB9`!@Q}j&dVz)4d5YP^Dpp zoamj-v)Z5gq(p|$S1xuRgPG`WNB=r|5})Bb+8f-@bQ0#{WHH|h7Bj{y_O@Z46v&C# zZRgC-Drx8~k*jGx2eGEm33(XrGoJgR^kv;-pnI##V{V;;9K;xv!+S+5qkc%{*~iIj z`(DtO58W+>nub?hph#X|u?$+3=tj#}*+)ZDVOc{5eesbvd2N2frrhb~p!IX6e#<>a9 zPfOZBhN}H3{DuwCf|sC?^MKA(Ed8HzS4>3rjz$GQe?cB8pzABi-|?M zTH!q@7xS&_9nK9^d1u7R8PDDzKW{TfPNIxkP(R1I&-43XW4OQiC4Rr)*4Q4(x`kaK zCsRL1P(LkIP5rb`bN4db-x}M5-|o~;3+Hd#3mD_xym#azH=8l5Km9t;d*1LP#g00&yYA)tOzU1xwN&h+*(#1_juX|i(a?a91{{`xmalf>M4Ep#C z`lMXO)C|V^47USv1aY?KF0!?Z8^L_iy^T3mI_P|o`Cm9^)cK^&B}wPrxg_@!>U`2; zJ)n9{*^WC)bUt~rbv)zP$2ynv=30X}6MVJ5#G1o-w=&K!wqfpJ=84WX%&7)rHio(2 zo6HTKO7NYZIjM58N2#;Ce2SfIr0^A!8a+7`K&vi;c}0Uvy6Mpm}`1u`r@z*|U;B86 z{$Klk+|>*Fe!f|pWBPw}6N~|r-B8p23*-Htq`&t4{>$vaWnN?2Z2@=p)#o>wK4vaS zpU(H16Pz#Q1n*$xft~sO_q|MEy?hFFk?xJA-+zR0Y7@^pZfRRx*i$gic?7k^bI12X zZw>cYI;h!e;FnXD3338?%VD2$4s~9Sy;6Pr3yl3d|33Cm2mPq_k=}!`hfP09zo&hu z_LbU?QeS*qjI9j&Q0`~9O+Sj8urGCAi+yVP(Z-x_UBeyi^r7VQ4R2@c&*bxOUIF`* z>+>D^W7+Ip9;+gshmz03$mjLsGnIUnlFyOMHy4u6W60+tLwL_VJ)pB>3(Tk_e}y(_lOeLwaI`5Z$z^fz`t(U|b|Pa!wLHSiRBJ)~w3hwh+#`s6^bW|R45mj2%fzW3JupMaas{P%wV z|DD>-f914t-_T6~oW1(Jdx@&=FId8}@Snvh;tDwu^=JDd@<9#rMm5w2aKFDW{-9Zy zmjA1g-*sB1{J}Ksw@m)ces3c@MdNz3R@k-m|7vT69HxzVx66jj^Ldl}|Fj}g`3){LWCZRvRkjhlNtWGW1ZR1sbg@0-uU z`>6F^n#CskRsJ(b(jVy!lUSSEArC}eM?DvKM~zH{3gGwhGz^71XXZzGpk9dkUGS2W zM)Z6F?)-VkzruAU{6~oY5!TA`BIm)qFbMM*kc^sqn{sT2q-pM}Je*};oeorDVvJ*KBc(04r#h*udvODx}^In$IIWuw;?|>O@UAZPwjGu{oBTd5o47i3h<0{Sztp&m^8xNwYpfQ{zONAU}ug*!jq3;5*QK zP$w$+CTZF>Z8|Ud7|#y)uf~bAa~>MQ+gN&Dc}-Ccc9M*%Emfd=HdeVog)d0wHEE2a(dzNP7jXn9eW{#xWAxKU_Bksk=BJu($u#?FOg z)EkiG)%3TR@ohd=%fMfb9r0jyNPylaeu$R4cM#B*@ZPWXy(1r+_7=LUEeBPHkw}=I z8$a{4T(q5GSEhZXzZv~jXh=HQ<7fKH_pm2T>ei+2Hud!u@_cBApP!MZNM7Q_xFHWl zYTL|$x%-YU#Iw(MWAy9~K&HV7raZK4EAX2PW1s;vmOPtyBI_Xy_dmcw)VttI&@>!@ zr2fgx+LKmL>0Erzz}?*%P?jjtK&I@Gg27PD;1R_(sSygq2TX}+jS z(-$I5Jfo0=Y5G~}mpJo$q(>e5gW*EVMgwOqtKmMWpw1VW{!H(Pn~$3zxF_wVZzFzF zKQAKJVMe&7ylK0vU*!2^=o=$-OlXOlMX0Gu_D$w#KV{lK_3VF(9pz%i1;)fE>G8j& ztx$K-c_4BrB=cRfFhU<2;n_7~H-5F9c$vUB;eX6Gk-^-lY;m^y3DB??;GZ;@=T+;8 zc(t#jUpLPbXCLzXO47u6Yjqcyi5sf<2KkCH`DRR*iB-L zDj)0D{VoMTi* z%4ov?`ttMR(BEf!Ke3*E3vl-teS-F-=O(aMmbJ5D@>&pSBV!{s^6ii`|KB7i|6IzS zXU5Wd$2t@Df`m1)!dY(a;JAYII8EPcu*WU2+9AKg?RCIBDYhF~!1`>lbB_E-zjhP; z%A@50V(D1jCZV2`hv46a=P}RqC(`fs=58~kEgTMQpbqC)pWJ&UH0%>uhc0LRxjZr! zNgqiW?HAU~%4@>9SGhvGxn4slMb-u8dseb{qBSNGoI6#i>Etf(6}0O?k()^iGP(p7 z%OjB%m~(evI0mZp$B@<<5bj3-uSQ>x73@!45q*d;k3Nmx@m=99q<;s>*~s5j(@qHQ z6D1)@)iz_k6*3+5nb^G?@HP5FQByy13+l;0eaZKr_xD{A$IC{)5XJ{+owS7x0gaGK zV!++VQQpzqNkJKThsC9z9G3_8j?dZk*;aQT%w2|>`LaGs^dZ%1)hqe?F$?YXCm;PM z-S01qf7VRnq+k41+G~WPbHv}W|CQZnp6@X{*W2+&KOWJ3EEoMrCYp4{|v)bcdH|%So<8)294_azMJ2G{rb2n8V#rp2VYI!E_;g4{)MO`_~KZgG3Sve;0 z7}jukUaP6Y{)7TKlJDQ$gD}D{#q{YD$lGQ}pl$SkG}M=wxkb94h@{WsyQ7|QkZ2Wo z*S`5=_K?iRt${2nJbLPdvu%0)=cv_hJ)n;0$MZb;YMz5U z?>oX`4$K~%V(!l@cHfdhGrwrSv;KgI%hZLw2XMB;goj^E!{?xV>T9gW&vTBIc?k;` zFQ?1Gggec1+8Vnz{dT6D3Yb%5vHvlPx;Yth*3tC-Zd>O#VOi_<^VcKIiJ$fRgr3p{ zxg)A~>@7297W(1QlZ{$<_smM@M&BFnC;B5Zsh52JsC}W_@_8rE=bbj+{hIqYx586# zoC`7A8OLvhzY(aPMQ+4T9o&4mFYYmzcOooxdjaw}*nS`ECL7Nzn9W z1^!4k->>u8OOnq!UOwY_KHop{J@TEHhyGi*68%S*_rPrg+Mw@+{wwlE`2L)Lf!Mu@ z-4p0!b^F#eX07nwDwk*$b>BJcGOTn2~O8HL{p6dID-MAF1W}B5q%X)37hZ zEQ)*sbJESXBoiNFRDNVQcD3%Pu;+81LajTLYU-_J?7`j4bC~@5Sm(3<+~&Ldy@WY; zFP1OKRuT7p%x8~71$Tecx;tWDy>)`W)9M1vAd21J;XPQ#JJLe94z7et-~u=cy9(F{ zYhfiUf%y=>!=k2ak6BG>+M%Y+&-Z(?CkvS8RYM&X91#3DN5ta_C4EQy?ukIwPK*6m z+&+}ftiXRD-M(>sD0!cbhZo4u{NEvU?B*MP{EiKzwh>K#D4mmow1x8ZKp)83dDHoj zyOBLEf%KL#zll?>GBl3_c?~7sxfj+Xa(_IYP%>65tO@H-rc6RfU%Id++`}2S4ns@((j19)>9yz!(^PDE90!MVXlnhd0e;;lpkZ* zUdGh0NA0}NJ}ttCyvUkE0Pltc-dw)9o(!AflKm9LHK{$9NMKA2%$C&U-GuM_#opbl zo1DY=^e|yVLR-cS&fl>PQ=E`SpT7}v<}bAWxI7Z|EX>zehZTmYGN)#oE@$@G!+J%vv}9jF=Zm}`|To|SbuvP9+o5gq5M|U`Pfgu{Z+_*?6Z5B zv5j+stYKu)uJ+O%`zzpL>{#!K?gsABP3(az!Tc@cq3{GWLH{m(D@X%p9eI~4W<5*8 zERCciyJNn?jG;O=86UB^OXd{jG52702=*WG9(T3*&XmJ9_;t~)%)17f_4G70=3>TduE_MH;^OQI`V$Sp|T`&7+ZlDR)X^$zz4 z=y`JYa@5=>pnll5)!7*j{I0xnA2JBTZH8LI(evar!eW0a5FLXBu`w(MKIF$B~3?uXXB(e`odC1y`?xEHs2 z4{NaZGul4(h%=IXc0**PXS1Hi9ULm7=f)*{Nf+&h9PYtzKcfGj@8Nx^i^7^^HfMV> z7^AY;>(yD$)Nn_68<+Da%$d(%*w8;tQ0&8cPMWrZZ7iRy%<_D+3YCacmI^>WoB8TF)0e%})@$+8TABMYz*f+|6?fmoy_Kk6OIPwVm9!Z!- zmWwn&-Gum>;;!jVk!GtznvVeNnpf}`6K3*Yz&x4wTSQ@7I4)&79Hm>g+itg zM%pfxUUCDL@o9=UJ2!y&A{j-1S(oWRxS3`AWCQj()OO2&(IVZk>yF#*TR93#JUs?O z0btf+2~==AED130iFr@*&}+8Hv4wnk86k392~;sfYXGDvD;o$mi*U2%@mUDjN99t$ zZ=cOj$!7o;nm`5&hMgR4t_vy93r4^sm<`xvlb&qylD!tTz>fG&W%OUk=kMt-4~Sy` zaSYfDmBG*8;dUTybE1$8-5?hzo19W81Hw3-_>L#O6`HR7XJ(#cu<90A%4<_uvggtmAtcMEN#m{CWK`LayC@6+GfZHM2FdE3u zka<9UhLE2jITF&iugv&7C8mKr{Lxk+?by#!A(AH@^O=on^UnrbsJQ1guDT?gKQWL z(_tPgg*C7lDupej&;;;%+F&SzS+GE43}KI13FL1~1?=J{?~@=EvS1Vx!yH%wt6?K- z=M$PhV@QJ>z@VT6=EE{r3tL3aAilArVJv>e5ieRPB&~&{t+0yeJYk-R-!qBltW;Pd zQban7cCl4~uqHNvcCcRL>{6~##_c(cf$%10Lj^y%wu)|cHsI&nGPZr-ZW?Z;m2gzGPp17~?1tVY*%!b9V25@(M6-yvZpcjmWS+JN--ARxJ z#C1b4%!g&LR^-M7Y`Ito>wz@gL|PXlK`LZH0hB@+;BEo#ZbrSZh|dwka|>y?g|w6r zR~de9#qX{7y)_4Lb1Qyt#r>`Ly>&fQ0PYsyZV~PlWx*&YhB>eVR>MZv&h{~Z#*hX% zPyi(`AC|#d*aADuGO8?2Ms|Z-C=&S-W%j3yKv=gE*6rmYci?{s=1bOy+==@;DaSi0 zr#n}{2H3{W{J4OdyRxAW$lqO*)m^x`Yco`e+>M*NF<;sX)`{HH1c>Ke;=8Yut7l2a zGSYTG@hwjgd7v?@6e-UF+^;ATd2lpPeh(4GLt8~w;`ZSNu!ikI*gZ-<9^J)uM$+|X z;(rYNW2he=48*m%0IEcum?QFJ8Y~rgig=!?5Lq)zZ`?A4kC&Abq=VyQ>fu0O9>aI6uvXm9UljLtID${QO)Bg!}Vq z*aGU5dNNdA~E8R zO&3cVz#4AC$c93g1Ld$0c8FysK{pr;vpFfpRMkm=!B7kfpaQBmO@_If3z)gvI0fti zW?nWF0%3d0V6(8G3~4Y57Q<@5JVJczuCXHXV5?ZsR49QZum-k?#cG$8fPKPxu@VU< zk@O|bg0)a7R-Gn57|emKIth%JTF5%TByt>=PI*70iDu8m>C00H3^(Fyv z)!QN#TlcN{_^Ce~76WEU4PX>tmNXw$i*+z&2loQvJQ#NeZx;PYHS3UWKzN6&gl%FS z+61zJI1eoa{2p2*R)ZoagEfHuuoS@EVVE@}?1s2)hd{_tI59gz&9fv}EP1^79VaE=@W3&d)IeG~jOsoJ%3me2r z#yoiz;HJeKv0CD%CH`A(6{{6-wmsq*2$YF+6lpvP|3{UJmD(86 zpa3vS#XgmErIN1HO0kZPLNegy=q$jlE&kh*rnV`N0mRXE3v3tb7{WQG7)p7SBE9XJ zz*-=@_Pt=RSRDj5z*c_xcAZ#hxKEn{OJFtNHjS|OQE00Z>FZQ3RyzLDvFltU7RP6- z49vO^e;538*&$ZuXjsGciZoatRyW*rTQ633($^igJ+fh$SUvIEvsA2Jbz!zx$0osi z!0ym6Zdd#Ol)k+QBNZ`eN3P^z|eD>{K9a{WAbLfH($}K!sQX zi6e)&a;o?Vy$xaw8Vu{jI-yvs!Gt%MI8VfENS0Vb+W~gD(Cs&F!YPwjbBm-fcQUSQnUkh8rI<*Xz!D`qD*pEhi z8unvK0sAp4#X6lh3vyr-5M}}CKZCT4B^_fMi!}~6g~foM@r%VebE#No5&v0}U>3{+ z%+D%^HLyXfBHS0@zKF0V zF2PSJ;a*C3ml4Nh^ZB_!+|6zPTY$7&f!!6G0Y6ug#w*KV4PbWVHnFZ+E!G_Lb2b3_ zIaOj^y-}>WggY1YHN-KGFz2DZuCZ9xla}juiZ!2bZm1B8?X}i|y0A;Eg_Fd(Wvy7Z zidc) zXt`Lc3dDNM73=Xbu~yF$>k0fniF}H1*Q^xl>2+c~gP&)2h{c@7dJdi^tiK?c%UCZE z=Zm;|sYI;x8GzZ##Q(}@z}>5}fv`5D!WOY!D;4W??A}O$ZDMUK6YEXbbPr0mclC70BTkx)>jRn9b^Mxe}(y1 zm{($6iFqaFm7`%g%!UO}4(oulR_+w*>$;Evyh(O%`kf(*G@K`WCYt z1!Dc3wEw+|?MR!&`p0~+b|yobSl<)g_iM%aVX0U@&Jt@^u2?@2K64%GXY%&THnFM* zYj>Ggd$IsEa}ry+!49#RhuC(J*iMPq?j*6jT(SKeu_L3zj*fsrz>#h^~penKJr@&URlS;)txIpYfl3nI@GltGo)N0k8KGX~m6=ZMW%XSXFC$7GA$u8G*~(YIeCb_e`-SSxnNLLiN43&ie( zT_?g$$6xwRu{$pjJ0l4QGh>I?T}HqLu`>sY-L(O%6T2JncSGNeIJ%RD9tD7#p1AFa z>{TlEv6Enn*uCdKh1kaxiJgW2EW&3@vir;yyKh|}ef>y7ztw=>ez@(oQ|xTw$i^-^ z4c5a}AU*wY+rKfigDfD<{)FA1JoKLrOM$TZ6IOr1>Q7h$2x|a-2CNZ#AmQZ@Mh@;7 z-|XXyVVl^4CIN0w*eLekY}h6CiJQe9g82~K4yhD-XetobQ2gZ*Z|*v=hh>PJ*8p%c zye=#in`yK?Vu{!%HGw&R`;keI0^MLR6u<@`jU#u8eez1NM-j#;qr}cn6Z_N>u}2q* zecEWT#}LOD(sTM|u?ui>Mq{zZ631Blj>ApiB(cZ4FkS33vjMk^V|G!F*b{I!VU^eu zNypiw{p?Dy&xr#0oV--*DTH5~1v|w)cY)YbiFX=dO+!C@nb_wQi+w)voxe@&3rJ&0 zq1ZF0ba?mzdhd++0M|9C#WYkj|;Uu!$3 z-QF|KY0L#ZuV%e^SfOjmF{;qD#9T{m6Lqd5_B!^j8&c@{QZT~}ndnfc*~O$nHzpLi ziJY70e{&VMZ)sKN7V>W4`qmPRD0Ca^ZREES)5`ws*m20 z?pflVC9YS{THE2N(5|~uz1t9}@C_xpd^+FqndtnHpm{O?U zL>3BA0pj{QFn}bew}^U+GC;jW)LTToMZ_(l-XiKPqTZrWP;W8y7E^C=0m@K=CUl?= z35;V#p%-JwK@loYhZb~UK%s$3gU(Q56%2AJY^kW3m3cZq!e3YXe z?dZn{rWG1YM?T6?k9PE982oo;a8{vL(~*l}RHGT)h+{&b*9>H%7}aP-C#drpbzYkQ zb(TMbR1>7+u-giKIx8GV-#x2zRCV7_JJm{Djrh8$3Dn0mv+4O4HJ zdc%Vl1<$dZxaGMhK{cAtfj%Taz2($fLEH-BRuH#>xD~{$=)?e$m{jOJAp?0J?!78B zpdHkEZy3ZSiAxffBrZu@lDH&s$u{(W=SYrYR-yNadp{p#s6`99Fn}bew~~4*iCam% zmDF2Fy_M8kNxhZSTRDVL%qa8$aUT?*0uAWE07fyR&`1UfQHe%$g8Y#Qg+4Tpjbc=z z8Qq9uLZOdL@EU!@tRK~*1A`b>=wk!fC`L7!(TzAJ6dE;3T7xf@-71yhBQ4H#>qQ|OE5WkA}Rm6Wy%-7i{N5}uAkM&>l|No4d6B%I6 zi5j$leiJhaeN%u|FxzT+u5M81Tl#;?GfeV&O!h1EU6n#>n4iysp*2HDDfB&g-*eAr z!2d@n`u|u8UYj4M75a((KMgB1MU5%)r)CuTnI1p0_Y3uZtyXB-1oKRnqZ$1Q{YL(8 z^!#m1q2IGW+*BvDL%1{l?4SE?}=m)dRslbrJ5&H8t2*c4l zbSP|+XO1Xrp>P}s=^_YQduF>VPeQ3uZ58HK%GaPD`aPvM{l9KXVogaB{^FX zw^f_MTlaw(vgwgc?QJ_1-p)Xe!Z}3>Z%^*_rQm#fVz=knb|?n@b|h{`X55k3Tw-%M z+ljNCk_zukkDVL9-Y&%K!d_mt!n;<1I=fCPyju<`k-&_?yO*E`6AI^Np$rM}Zbso7vJ`G6=SF(n)T3|=5Ot%a6pJaWKnV%y6=}Lur>J^@6 zpi$vxID3Y9o~3?oT;cg63NI*E__<7UD%_WiUWFHO{=6`u@C!9aDcoO&X@wVcE4;W$ z;TN+ouJAy=!Y`5ga;?Izlqoz&kHLh(uTu9_W`2!1mr!pg4@rezuTz-c{laf>7B>}s zD+4_Wzs(G96Z?*V2GBE6ukgFndzbU2B?>QVRCt)&Va}EpgZSl>3a?;qMKh@X9(CTM zM-uOozY_c&5&mFS;gKPQ`CTCV5j{WZR`_H3jIw^h`e_XP3V&9L35Ca~_4%;EUo8ECer@9pWnP=d=BK#}))9DKH9blOEh4Am=3a_0~c&1h1b@ckP~ln5 z|EdA!e{=m0XaDreP&N8wtXGO@8KFWnV^T)AO9nr?4SrS|bF$EcUKx=bbjygQgLr;E z8>WdOG{~^nx2n(v>e$0F9CBUqT<*OraPB2!`1z>B0A^$a^%#;7b3sh3Uq)JqjJaH| zKPw|WDPu$KGm2zvj7_-S^k3v>=74;@Pc$}TZ!?~2^9mXK`I@msBT_Q5IL{iDu_fnQ zvTnt*Z8arhYhts@Wo(ltW7~90%Gi$h9Ab7Le+SNYEXKHu+%ojb*r@=6GInN;orh%X z!n(_VjJ!f{zbosm-0xO_Q5pHAGWH;54{GmOi-e55YA`0Ffc*kq)Bj|Hb#HR^q3=HJ zG77Um4u6(q>`Tpkhh^;7B%>%F6EgNE=73fi2R6$nCa0MDgBoQVOznfmWgNo1e4l5O z^vgK3O~zqWG7cy1aOxdCE2Fd=Q!`0+b#!YcMS1(mYJaxQz45>t!@huOTJlidGp{#=!nnbut>+ zzq&%kHUFBFaczT)CTcZ}$hfWueKM}kLYs^m3~+t}am}@0y|D_+cT+hMGHxzJuZ)%) zbRi|GUc4oUhj%gWpWP{mwk23B^%D6KV)ZlwW zqpc3)-i5oVb#JbW`+6`Y<9-)~s0H^OrQqxV1Kr|ZGDlp-L)3U=5VJBKEt1j2dDpm% z$C!)vFXQn}49j?e=X;_R{TP+eO@24$-OV8WN%}lFDdVYX%*c4UMMh6P+K`elkJx!# zGM*vtnJO92#z5a*`p?e#_1OylkrwLxPQAt#ychGmysyNw2XI~WGt;hpNwUB;C`6bWO=iU z6`b=~-AI!AK0Q~u7?ANnO2!E1ALh#7{m=NAmG?j6;~5#FH5irgNjZ`-J|+LtRwOVf z!o+to)C+PPLx!;ta3o|lSXMy|G)gXR#Ck8;BZ*$NqW3mV%GQOkEcigWbXHA!k z@9FdX5U7*lIz^3Chm0Rg3}RBok1??SV^YRXyly{@%9yIhw2Ys#Q3Y!Lk`HSBDiA+S zjcN9$CuIDVg*q9(6aRZDm~kz2*HUAKoS9)T!#d8_m7xVgn3XZ>%J_@xf0{H$ofyCf zrZi_g7X>IstLB7?kkp*8fl|#evNgvo(VPvkG-tC(&DpkIb9SE5oV~_1r>I$TN?4CB z)ExetWzK1}nsZK{=3KnOg5{hI^D3X&>B(GJGf?7q2Vu~CxtVl^F zD$#>!MGmb7*Zdh&}c#cwtJB6FL>CAoj!-MNVqKv?BlGzOo3zikwXRDcR^yXSFJFcC{ikgf>e5Lblv zmPi9Nt|0e{2}Q0X{wmI{qF*DkTy3I5k!#4ihThjQ>$O9QG?jsv>lzffz5tVo+|aH_ zGqW{wek1!g#n7V&?<Vo^*I~BQu+&dDA+(}#;Gq;T@ za#x)qcbj1U9_qIjD{?P&@8$kJ&hF>_{*)pe&5Argp9jVid9X^6hq6H3&U!^2rq;vL ziagSx$fKNfQLn2ohU;fd zMS2ZI=4UIipiGhHDi!H#RAgblBG30K^1_rNi#S_M>|*j3Q|CqIez5?|@L~^$8OTE& z;)=YKfok+&RFRjNC#uXVfk%uaD&a2G$ zDtoUEA*IM`)Of7~%>7yqMip7&q5#aXq#fihnNnmZ6Fkchu|vcTjVSWEfqc;G^;Qgm zx^GbT4PxJD0^+Pzuf_ zn1T1e$TzhZRAhCRBHwcUE%Dz?DYAz6H3cX~6R5R@=UFqU$oJ%ZpN}duq8sFWpHd{n z47>+MQuImDC)EzlQuO=5Ko&Urp$2W}#VBSJ`7sxDm{sH_YWzgcsVPN%rpGVb|5A&% zBEM4OS8D&7RAjmUt?0+NBD_aNek1QU@_sKy9k~CU*?*r_WG!>AC3h`zt)=%`_Sa4* z!uO()nM$;PS~FvctV>4~*jv}9$RC;D{*Nwirc1^ZZ53U*!BnoxhTp zRpf7C{w`8frHY0c6b;uXYIQ1VwjlZPgZE9%xN>g8ZUQNIi+MboMkP3JtlSJ4fq zvjJxtwko=DuA-aFD!OR_DizJ-Y%_8;n^JW1Hbt|t72R?`(XGoB&1Nqr1Ju}_+#RMB z-KAU6ymZtnx@!s8-<28o3>w|NUC}+Lx2FMS-HW<=wIHcz0XYRcLjko4=>MNmaJ{by z^7k85w5VFq{mI>*{s+`5dLY*alFw((Xfd-DPb+#5H4f(fU~&&(J%qKS7GsJY+NCI; zJ)?(bqFK>WW-qN%^oU|G!;vM59!+fdh@!`l$9r@1*fSv*56apwz- zit>ILy@37~rej7?-Y=td?TTL1t?0$0ieAG0CCqsVx%K4L4=Z|U3_XfoR;}pe#9e_a z%f!E6h!I5_n-smeSkY^k@tS@`uPsoN_r~aT9g5ySZgUO>6umJQLyF$ipy{MW!;LZx%*mG- zsROamcA1t?gQQHGTstAtDVOPHpjD>FxmSU>OrKnSHkm;eCS=C?WTu&Dk~z0n=K3Wv z(>rBuK;DKUGB+BNxpA9Jeny#_<;mQfvn?8AX3=ZQ9+_JcpUq6$kiYGu%p4P?7?inv z4Ak77`0a_^o?1Ip$=tCFLo#zSL0)bL`a#W|a=_kBvod$C$FR&@sId$8d5to6rT(tf zAa-}j%uh!px-lwq4;T4hZ;xj5Vg%&xN$ow$K^))7nR~Hc&?fUgT>mE}bMJnc`*6Jv z*M);J|64C}-#l==U!BaNLXf+EtIPwcFe&puVv9LHs2$TX4<_f34A8qIhJKlcni!LL z7|(ThF33Hc_`~}^jnZ@!p%y&H5kd|sFf8*(VvmetTINyNC`Jo7JBq!s0#LgwA@gWz z9ZmhCsdF^7kI6?bW@H{)DzlvPa&pTjWFA+EB>!W+^gg~{<_Vmizsha7y@B-x_M189Gnsi~3{^n;5h}D`>(UU&iV%H z8|=Ty`I||Zan|^h%(uE^@|nqedtBx_Z88(=CwgVRn~7GLd=@g7vMys?#{O_65;B)p zU{dCa4w-zWG2i1gNw&y*pZ)haU&*?X^A9*5;e3Si4>|vc{g2rHnElZbnV)1JA@fu2 zKdX^B#`zep#pmg0miYzi7pz~he#!oLIpQ+EV*P4D=Bjp?{M`=o>k*j~%`(4X{~OL% zv##d+Th1pr=Q}y`JI>dzzlQzq*-sVA{2?82nLl#>Q?<+~&ZmZC{#*uLlV5mE_$*=m znv^-+B=a}+e;bqeJFm&wLYXrz24$|}{tsT8KTE;+EcbtL{x|1;bN)}OELF-{uN1Sg zLc_Acow5w}=dd4PKUyfuWVOm=*^RQCB3Z5>%gdDIr(-}?Ky1v#psX~m(`IGOZI`uv z4#s4qQ*VP&S-h888#Tzv$i$4Sjj?G=R%VH;&AMf6PQA^WWo=O`E6W5mw#-1ktgXsq zZB5?Rld`fqWNkyvHso*HBWt@pSvdo;wjYwULqgV$g^3`=YgXr>uR*Ev%6B-x^u_Hptqq zNLCT~MYFOFNSAeBA(*u|7vvs9pM$8!d!ltPIR}r*I)t1c0`+N^*9h-?> zS>@C(C+|4+k530VCvacE94D4xR@O;e|F2wDWd;(mPA2E%0a>Tyq6@^F%Jr%2RTW}L z)@k{m{^>#mIxr&Zj4afm56o3fTy;H0Wt~}ol&rI;dG>&;8sg6({v6`ZO$X0;UNPEb z)w0ifm{m)S^E+i-P>NOz%epWdjiAPb)3WN=yNGAt{mi!%gZb`|ywFKcKWj$I5YIYIdMf_uxAntMQAD@)<1bf{D7?Jg4I?6FF>nWb$Db}ZZ zW%cyPdS+PGvrV#k%Vf=WF(qpO=g-lnuUghZ`aGY3F;IH z&@Stx5{$@tISbT(B?k5fg=Sf==7Rm#sP|eG60(-$VNli(&p*^J>vd|pPK`IXf0MH} zCuGH`@m7tjx5;@Y2h>PVJHdnLZV#C$^RC!?}H zEyRGV&oa>|Ym9ZQ4sltZ=b&5G7qzm!tirUcaqhorleMZGld^apvL>j*`;hfbQr7Bv zS>G0*SJotZ-(_G%)|zHn-^Va4E5&t+y&tIiqtGGir#!@EO;un@*3YA|ei@SWD>Z(l z&u}l<@=pvsvQ>yd*?iWs*Bg@^ zYLp$$1=mKm>^ZfVmK|X~nuWM*vkZN*tr$9G+u7jU9+mBsVo0`I0`9#k**@Db*RUmsyX4rB<_Eyx{YFsw&S@za-NXX9SJiABsHpSpa{w1;x$OL^4B=$i171O_%8pSEu2W6lbwdlk!=zDOkY(6vEhtTH`_70hp z&F4qEqyY7xcFBb7LtW70&>E0`=pg9D`=@|;7)A4|>hG1-_KnuoXH{_uSN!eGB zcLi}*F!vS2T}j-PtXI{5y{qDwmfc8PV==1HjBbp`zFNpd1*m^@KPF`JInus{y4Q4p zde;(jZ5=qjc2;&%F@|OHdD6aaT=wR{>|0rHrN(WX-PVp_*{uc&LC@Q%bw{P_J55ll zEiU^m`re(7Y1#LT%WkLFy%}hceV+^J-Cu?g*&XCQkOyKPY(=N+hsb|uPOabLS0Sjw`?>uXy&tF6<{FS}cy=aX6Jm;Ds6PYua_n)*-o z$?jplhq^sH(>&&yNBw7t!TKz@&$9NGfIjo7JAYjE0%lw=CHuK@BxLs$f%Ap==)kP( z=j*`S{GAf}1!DT!WiKLrF*O%=$$qg~_COX=vR|UdOEa=xrq9dNc_jzr4A!F;6S7~; zMvd&(46wJPS@sb3ucu>B_M5KkIL{X6`YqPCIDczY_S^J*rvT(6=$9Cg{cZy|Tbd7^ zeQ8SevTBUU9?nH0W@RsDUC!AG`m9LGelHK?C7Wcw9|O;^vIG;dKj@Ur`@j7m`yXY1 z{Lv!WpK$*v_n(f*{;Ws#SS7|~e_n+~u=hDNzo?V_rNBAw^Y%FNk5l(6X8dXxv$9vU z%Kq9!jqC|(enb6lsI|IVHt+fNx5Q0$U`qCPwIF8=>zbtO?;B*Nm?bqNoA-VD$2<(m z{)zpcW@JxQ%l?`3pUMA)p1&}|ucNZ3nd7$-*}s$XdmBbT-L+X@j1j5}f^+fl9DH>!Jdj{bis>_CMWn&SRJ?$ax$ zkn8`t$V4vK-#39#Ov>4>Nlp><_DLMSE z;2cVi!^Y(tJ}l=5>K;kVQ6_rjl-0>OI$O>$IdYC=J(eEjU2=}2-tjRo{|TI(Feayh z`X{!_IjKR;$@S=wbIP=wQ_JL3@hnx`pT_m+e1;#(Fum zE~jQgABN;ynIY$@DmjhBHd6cQI?Twqh8ow*%DI->O#`6*br~3xbA2V)yTL#@*lX^W zb0c+b%EXAAn~TsRhxbCKWm?WHO>%DK8E%WoY32D^Q*v%k%DJOi&YjhmmD4sXhtIUm z-Ia3g$&u4u0Q&M-*14}n&i(9lxS;+62{{jT$$5yqhp5p>-OhSB4-52qgkFyj^Ju4> zt|E-dd8|#&ZD8*w?$mV?~h5jpewFblTuvX6VS)k7g8R(JI&w2l-oJDnV7RS&o=f!j+s}n17P<$+(>F+U2YvZVmb0Gt2i=a#HmFK_KtPYB@huVp`7B zgq)w-$$aZ*YElN!7w$bpPq#>P&d5=-AEuMcY{onf_XM*Mi)lq zZW#N&+q_Qh=F@VwaKSTd!Lx3`yj#RED>thM?I31Lo@L8%xm(e1EBbBKhe^3x=YqVg zIm>3A>|wdvl%q@Twt1jV4)wRMl)J-}++1q!%q+X+gW9{5%H5s#{C>H6GH*e>+`UKS z@_ExO>X5s?0qzf=PH~&ugPY}+jLAK`UG9;+a*v_Mu>!Trnen)PF~e~)a*r z3Z009*otCsRzci}WuVuIqjFEmM;(%K|Ca;y|3`c!F_r9{oD2G%l8I)yr<$lm52oc- zkyBLCXq9_m3~h4j zn7xkvb(3;0Dnf_ci(TY{*ozZ#`ON5E5|>+F3hLHR%e|CZm(uq#>RiV8W!ztplG`{S z_nKk3*B8ibCZ}aY?k&{3twe5Xv0OeQxp&g@F0^N0M(%xCa_{H*{-j(!1Gx`S^FeBK zmdkyZ`-cbQJ~}G*u^zdPSBqc8`Ap(I*D7}*Jr>o-eX&vQ zOI>nbX73ex4`NBW+@X}**NJ^24)Wj3MZMfOXYqEh$7cuktueW8XQD&yJM?>pnh6uk z@NOQ6UCRAZa+eh#0dj|%FeP_+rQ8+dt>}^a9&yQkwO~Z<`_z5E7QJ#;60?%nmF$0z z58_9dX{1x`hh_M8oss)dImYCET#9zNqtqKEZ**GjC*1S-!u^!`pH9mCjOQE60{LUz zaz8hako!d;`s98|+?S(r$9b0Vq};EF`zj@O6|rA4{{-jX6vt^Nt z(Ixj!*4aV1e>2D5^#7+2ZSs_ZL3!(S%H!v=7n+tAW#-O~7+1sQ-UM6vwL-IDOk+*raye;xDCNGOxTheRGCQxUqLhw9W z3$2)v$M5c5Hg&U^e;ev;TZ>_N+cn6`DVMi>mAoA~a@(yN(gD2%3QVHTqnB~wc49Po; zv%`oxoEoKEmvVgs^Bh?y@2DK~$t$aocQkVxO^st}@{Y?!o4n&$k0+O( z?Op|SDiZQeY?gOYjlBP*V*n#a$*bhPvKoW(PA&p_r;v9F`KM-sdR46a{Ps@EL$5r3 zW_zdigJ(Y@2c7b&vrs4ROatYh&RNWTRtKne)|kArIXgQSob&VAJG)OFKd-%-CJf6v zhnnYdeO@t!FfOmQ2*jNqLp_-D{3&_-toANw1M^%kBJV;M>|NM}S$P*#$-9_3m(x=YaE;QhB$Kck92%xwR3@cUv}!Py=#q>jiypo08W` z{nmVxp#kk+|8{b2r^oHY-##wy4r1;g|NlhH9ewidq~@I+n3mU;2d;TP@$Mr2ZtCAN zD*mgDax`H;-o4!4n+5vaOPza%0M@Q%q~tx84qoHO`sF>&Y>&^#d!j{NcP7|- zvIM-gPbTC&m4PCV`&1`p7I}-wU0et1y_f^)zu1XMc>^VA$Bev}N--$!A?104C(| zyMh-dFHT&1NZwl+s0Q=A&Gp;#eY+d8^4=*yqr3!t6AkFaxV(2=6oA_Ac7QtXvcHtL zrQ|Oqb}2I~9h0|=8I}>ZtP3OZh7Irx!LAH zTQMo`y(}>Idjs;4#3akn59+*Mf*x?alKquK@;)H`gI0MX^dG4Ju^+PcVG~mFKB~c} zypM_hn7R2}>5VemC-nZLQy#ygc%RbyGjcwo_88}5?U(W6Ee_zL2Hze;5X8nVHf7GHK!}9*5&Y#5axz+n~5Y(Eb-)yhEznJx} zxV*o!(1sa#|8&V$9_leJe?8Xq;_^e~;67Z4Uin6y{5k0ul^@B+kbJ%i^`nFG%}ONY zTUlV=rk>p;--)3KGxFUr`CbM3Nwfrsf!Lw||99!qf z&(6k#{B8Q=Z%d8s(lIN4dvdpDe}@|RJF>SUIl1KK@*F!g$lsZ~ok!*G!gU_!dBpBo zE`PU5`Mc+$Lw-KFd*mQ4f6qFke6vT6B8_sBn{RQ|CphUAyim(Rlfaij8&C-(&QDzY&y|HLNw zC(+}iUitqkmS0IuWw-p3**}GPr&7C0@=r^be>!JpWXP}1m47DdS@RGt^hfztlj#{L5-U?&WRr8|sjff5nLW zD_i7WMg6O$__xC58d{x6bCxCM*i(R^6#jSe`k*THhQ!T%D<~d{@wW)mVXcN?RE0+&6a;3 zHSX(>e}696@5n>9{0F#yU{d~rP4XWSTI6?Tp;`XJr5KU_NEMjrQEEL(Y!@@}{_a24 zh*9~EbN+Zz{u2e5mES!s|4BSW{iliL{o0>LpJ&oR+_Mexd;8?i=X^nh{O36DE5?NU zh3q}g{R_47`-xrDEPpY57Ej54k-Qhj8gC59f3pZ9^5ebo-(t46iG7FOd^hR8TZU2j zOR2Z4Uq0_q{_;{#W5u-m_j=?fYvsS6EuZ%l|AP+sBjkQa{71P+$p5%T{-}Yt{7;$l zvrG)hA8VEWc|CZpFJ|O_N&RtZ^WNZp)g^ybiTtk%LF`1M{BH{6udbH=Ejg3a{7&-M znDY7A@29dbEC0s~`TVT+r2wIHh1C=GdqegP2s1 zk%LMQo6(O61sij}G1r@vf!dqqfu5T(!=_0EndvA8eKH3WY{vO!TyIA1=7s12wYQ+o z7M+MI$cmvD>}4@a)~tdp%h01>D+7g~C!c?Vt-0R12HhA}kWFrO5gHV1W1+Z96OW0a~p`+g}S?Nwo4_36yynYNGRAf3)I_{+Ph_=8szQ9{q8Z4w>z=B zGfO_b@|iV%R>2-z?@@zs1$$C zeQYz)kDpR-0&4{^6>$Y8)`PkyWr6$uWn)@FWxIltGtr^o zlu8As<{+h@in>+IcUrZA)9HUYbDTl_GrAR27lK-6=7RMs&d=&na5nvFT+pkA{^ztJ zso>lO%qTdI`sYn5sIA3_g7euwe?q|p>|Zdf;6m=}Vi;6#5%XQtqu}CP(C^|>bbz>v z$B@FTf=kG`gua(>cFBx_dJ`GwM6ZHNxxbYAOPjzEEQsuWyl zpiaS6nHW;gSc@?QR~LgmSJU?z@~(+1xRx24sMl11go5kxkyLO!``0&OQo#*1Aiud9 zvkGqPRB#jLyw3+W7h_lf@Abhg)ZzU;xFrjm-OBZ?T;H09B9MEVi%j%^nA?&HS_eUm z+dI&s;Er6x!Rvcxn}Rm_we>2vYe2!>%^>!kItA^8AopJ8<9qAizHtTjwWApr-{L=ut2)4q~4n=b26g&t`(XXW8p*S1`X8jS3c2 zDR`~`O$z$5FsWc6b3C68YQI2CKl}aE>7P}wD4}36@rzRmUaV2T?-;=V>q{nxeQ8R; z%j~^8q~I0SL1r8rQ1B|R&1=+oZBW6IY)mT{YF6-i4w&hUPV|EFH^vq4_j!UhGm(oz z^n>~N-6Mz#F;Fi~k2w9~)Q@*5cq<)cr~-Z8E&(xblm8C2-l@c}f&}}C9tH0*%e(Cg zmXf!WI!h-MEF*4NBgPaA7okJJ@&b^voF2=k6|AU5Qo(zfXi|_g(SmUW?^l7`m4%?! z2gP8P5qgdE;NR;6rWAZg{)hDYkk}7PF^WmdDEKG~c_>07S}_P}@@E0T$J~G1iCG1s zb!b9L!6#gQ(xu>2@;{~DXFS_y+>e=P!;}JkmkK_o&KJz|MKjp@lA2#qYrF<=1z+W& zSHUV`R#9^m&;50)f(aK53cjJh4sq-`YzY4q-(;W)kZB#hgmT+&0Am1FUm16-ysdY@=qyHknjx^LoX$q*iv0V%t(@2UD?K z$=MCNQ)>^-_abj^`WE&owqKuO2h!&tYL`qYcEqq^;JFZw?CdL$7NUeoUV4mmc_d*t^*FUP*q6x(o zlec(8u@{Nq@8ic_BK~E1yix~h4fZJZDtWI}DYm3mu_5}tPTm{L{br?N@e;+}s!;6h zX2ss2&bvj5Ep;)Y7~fOHmggz9g4*x#Jnyrvq{asgij8zD_TjW*A6F|j%K9nypY`*jDE4K$Vqaw|wu+h)oP8rO-!}t_t)}N{>VF$oY?7Ss1{GUF&YFJ3zOPm+m9N+j zS&IEg@1L0Qr<7t-or?Wjqu4JMiv7yUf0kmuO(^y|eb$mQQ?A%L_Wxl2PvZX~?{8}U zldd#nD{Z}UrG>hcW^g};HPWWEXqVE=q|$88opz;pIZESq_q1R_X=yQ~&8<}0`ol`w zfOR8RX&Ibt!hL3~(l#$uS{Cb89ZK7Vyc|PmJCL_?mC|nmnu{XC)b2k{$ z+zr!Fi$2Ze^UmCj+AyKH8KoH3+>Kq3y9sBTkiTgKCN(#cxXq}u*?{J5UVwhh-J%>L znw!O%MeLT9pvG3!NNMiYU7DMnhbhh7hWu^I5ZB!8NT7HFqa!>`d&=%)JY}cOh<RRyyy5rz{h!Y_=bk;Rz4qE`ueJ6* zd-tsdu8}$sbrKJeI!OVP0{cjv44TQUq)w?Mb@vidr%D05r-cBhpN=}|D3_rHs)2S= z_b3N0kUBFOXaSJcvlh5T>R$B#-g`HbItw(iE|NMs0%#(29|G{qQ2U?*g7&rvnA$0-D6ySINWT1)E0|J1Jq%K68g_QtgP^1Nr zR&<-x1Ji&8QV&A@pjJ{Bqus&aV=!nBL3zaT>Y;d+l#qHD>J0QdAh zSw-qms6XlksmqWyCK^EcShO)N7q~#`@^(^Bu#I%@CgtjNwk-8G^Q&DeP zA*rW>->Mc;&qUs=Hd4<<{W;*J2I+GTk$OI!wV=BYGFwzj>bfhWUR+LU#JTFFptT(7 z4f{yFGMUt?z|Wd|Qm;Ku>PGOi{t~I5!8>A4_2v*#KMOj~wv)Q4hSbkVfo-JTQU=^6 z^;Xp1rXcn6DF6ILQg5#(^$zgYjQkghNxjof>K8MCJEU&8M(UR?ka`!&?*h%;z@7-; z7OD3l{}r^c-yO&T(8jA*NPPf2WB#jKD@grX32>Lx2X~YD^+TjSgf``^RNc|Bm!~ z$)pK6P8!TFO5_Jtst%TF8;6FuankPMp|3%jCCTTR-GO44Sz1E7-!$_~0q+QBF{3N*(mNjv^FX(twww&Egb zr{t1$+F8=pG?5m*NL!EerD>#Ho=n;mS)^UnNZNHZq}`0RpNl5#j#AP#Yf1Y8u=6r$ z_m_~i6*$;H+Bd<&TcGzg_=0*()B^vegUM*uO{6<)EN{_ zx*?!7Y#Zr@gVu;F(v{Ydt{iPmLOYW;lCDZYy4j#L=Qio)rjc%;k#tK?ZyDYjE|P9# z4e3@jk#2P>>DJsJU1J65u%E4a?lS4NMUZZLCh2yd&W`J(+ll%wqwFqV4}R}O-Yeke z74V2TuG_zwbg$keT`Qgk(dO%*`Gyj>K)S<6Nq5u^94Fmz&_9mnyLf*OZMM~r?sNm` z&VmNkQMz+Px(k;{_c7>S1Z~86y319h`?7^}U*94f))cxQkar!lucIx*bh;l;lI}(+ z>29L#P2~SpPr5q_(*5%q=^or5z1wZl`)(w?VKwRf8b}}5Li+G((nkYH5u{JAA^jkv z*IXohZ6)a!1Iv-O%ANG9@kC6ce-`;KRFHme8tGp{x#M`A$|wD~cG6#JBmH-~N&l0Q z^uOF9{he*3zaLL}ejgdwWHQJukik<+25&soQZndnlfj%x275gj0_(^Sa+VAc$cqjk zL+l+gByS``Mk5*el#!u7-Us426z`>#WSH1QhRW+?nBGc;ndM}dbCeA8k-iA@mx9&` zyuUvWyH@YRGUE{rCZG-Bgm{ulS94 z%<%ViGThrph7Kti*^Oj$Zy=*@GZ{^*$!N_aqdl37{-tCL+(yQryJQS$Bx86k8M_6L zF$QVzXUUj^v=r3uUQWi;+hpv)kukfKjCr6_5JASmCNd5xBxA`%GLAx>F{NZIKT5`m zYh;{uiHx&q$yklw3#!Pt=p-4R1{U8Ttwu;MaB>D{!tSdKgRPDwD;+5GJb}3 zF13>p>u%#$NdNi<8NV@-@tTs1-)$q~56xu!vx1C&Au`^m08suWp0~6BX#H}9jDJPi z-&@Ie2Q+_gBjf!_GV&M6M1Z7%OtKK*4w>BJfo){+Xd#nlCV(`oB~2P5nY86((&duL zpd^zyi%b@PyFezt65tk@?9F6yR+9<)=cbT0GGTpb>Q+dmSkz58Nv0$_nUW*O)V-EW zsl{YUYavs{Au?swk*O!@WD|hjee22853~n>W)YqP)5uf|T0_dnG!*np>|`2-awG6Q z7WF5A*5pfMntGH>)6v#+JgZ8{G~+m#X5J>#tc_%8X8WszKh|CNj;# zdtCsT789B3rDVc>o~hvunO1@3sw-q#(@v(w8ZvEaAk(v#$@E+WnYPxG>3Q(51NC=t zz+E!!MwvaRv*$XQ_EwYWmDOb0calu|L34iufc#grWNN)kri0+=P%W7bE68*-giOZ- zG?VEqq`wXNC(6k5F6y3w?Ai{I=``w|*+{1M!RuMH_W{a(aE(motH^W#`5)dT6ZU&d z7lBXF)@Si#`W$sHgO@L_km;)uGF@#X)3+%5J=*^Pw0|rn(@)7{x(ObB+eW6}k@wG1 zGTlYpKY)A4yT6-E?V!`41R8+bWa2@KZw79V=>f_=xJYKYOJ?Q{nc1^smRupT^fsC0 z`0Zu~iplKmPG%3lYaf{v?PT^TCA0E6nKdY@J5FXp8JSH)W^)snxnwe1FOk^~W$d7f z^{5$Z9djVs39cq{sFciMEo6?!B6B2YMAefy2Klj<$sAup=0qczla7)(rG(6>pa~r_ zr(Ga(I?~e*ks0d?b0+xc*-GYKm&x24&n(dBgZv!S$vH~qT$ImC2Ck90ANatYzj;70 znTye!frB8Y$S69 z(k9ga;A2V|nJb&fJWWgH>7Y>s%m5wethqXZ%yW?b6yC9BHqR{tj+1#_0I-qF^QFKI zGS^-t^8)a?poPo}QGOxHFGTvHJ7jJ^J1fxcN?=t9aGlJn8vx|3xlHDD(PVD411P^9 zZ9aoGHXb7Lrc40O&9!8HwiG~q(`qs|gU;SYG9PLq^Bb*XKHLOcBlD4JG9N7_^P5M> ze5{7dZxN6MQ~?*sd^{i6N9MPY_BPso8?@ii0-%R|SM!NWWIlO?%&KIsomREhO^?Xy-iI`%ntpCiBNA_c7{RJWl3M(f~XWf0{qV^Ro&v zUow*UbI1|8B`^X2t)MGp3BE=a=)5HidExP7iLjF;5;P-k zkfj^)qVSAHxtQBziPHk0kC@nk?{$`Bq^ICL4Rz9xmXS%89w?IudOhpO(yN#(y^)qx zLzX_dWXY)`OCHeoBw6yoLq6(a4Q%NT+JzNlDJmn&z$&r~Dkn>EBUuKc+)yG*325S6 zhh-T0HypG^;5q6pS;lN6OZjTDRJfC63d&EfB+Cr&RE@MbMzTBwI&=M*la*HhWC&{uD^p~N|@-nhCl#*pdF?EKNxJZ^4GXbQ%DEz)nmKN~Rg0z>8aUPl{;&@SR4%i$Wb90f0LR*?ns#B%&PSxz9o4ZqJ+ljZ$uWI1<~EEkf= z@=-onK1Q8SkoFnsUn1ZxSw2VF7g7M_|6~VFlI3gAxB^<=7Lw&U8PwnpOoZWCv}Mw|n`ouD6t-yz5gC7_A8a3z59*sJ2A>;THg7y+~shu`t7#3hsw zmzYmnGTP}LKwR1-;xcv>K z_z129WriVbxDq%-+=wdTN(pEtZe%5Ji?~rJKRN_BN?chfaGN;HA8stt#x@Z*E*ZE& zTsi8N-yv>%34r$rXmcWHO{@h@5?2ucG!Qq513-UrHE~nWk13alt3+BQXjY=VsnI|k z&_>)e)Sq^dxaloGJ8?76)=YO`HGr~+pSbE$;^u(HQ%0Zy0Dt)A%GIF$TqS_|^AtcP zfVBB|)}sD`!CdB^-c8)%eBcUkOY8v3E&+`tcZsXd1x^yTv=Bi4 zGW21218|+V2Jq5wgSZu-xAGd$PTVT+ggMWxLits70LrZfjn(^zTcZU~e=PwQ0MuP4 z1)_mc0Cd+K0zj)#0ia%EJ%Dx_!OMEoUmp+D0LO{jfcFikyCEN_1X=;K_Y8Qzo*4HG z+J6T0o!z0PufcH-Pq9 zr9eDT4xnx;%C&;tYY{*huo^fH+#>EE2cZ84LGR#E0BNry?RBKRjK!K zE_?}h2z3wLChm;@pacNDH%N&xL)&B7f+nYSW$ zza#yhwZ#3QCGH+*wIlyQ6Iq!`vPy`ovKq3=L&)l8B&(;Atcq=9^+CSx1+p4j$ZA44 ze7~`BH^^#RO;&pvS)FBM4X7t;Pyks&E|WDZnXD0a$%?hFH43z18ps-3P1d+;WKF0b zYmyW=PS%v$WbJ;ItZ9eHntqF{JyACgd3|q?wLfSK;K(`rEhX#zMzXdl$$GGgtVci(F}?L|{60}e)>A-RCRxv*{@E*JJ>Nvu zPe2p#wDoK7{w>=4u8^$PuaWi7A!NM)dN&)%daIqRzk3d(vN=HCaguD#EC6Nw>&X_7544jla39%%kRG&+ zY{Ah$3vh>QAvM4)vW23pP|yo2BU?BDZDfl;oyar*zq^4>w;N=ODg>Iz7OeovfeU1d zi6>jE6etDo9*4ff9Vc777N`cUku3pb6Yxw#d-#rKOIl5~WIKR%lTjz77{If8B>+BB ztH_oHnrV$>O9%Z74#4jo?!aZTWukmf0zj`P==K8r-bMhwvp_rRF4?l{fLmnivyE&y z`M`Cu<)#6L$d(rXw2-ZD2-*5cfhMx$X91VVR)F>jb_1Z%zZL*L1HjjSJ7g;?CtDH9 z7o8>Bz*e#i$^_cTR*dxG8)O??51`E@X!z0pNW&${=pCjnD$% zwG?zq@f?XdBT;u$1aOjUquqf@0DP2zhjGzl8{a^-iAbwJyORk(`cymFri1nj^l@eY z*=Dtpts4B#0nM6bvSCliHeW%u+A6XwXdzpjl5C4NlC2)Um!2ita{O*sO}3Rs$+iYG z*Ipvqy5nS9pG&q4g=E{w%+Yv3VZCa* z*+#a%yOZsHH2F#5$T~UzV z_1)z63uydaLVgc&$?l#>c4a-;jkn0|s3d#nQL@LbCVOf!*?Vs!d%l+J#Z6={y-4=) zX=I;zh3s>rWM3FfcEou0wa3Z+EZ&;~$i7EO_SaDF&68w*w~Xu`pzg&MvR~du_G_Sf zqmAshZ=D>>~Yz*%xS zl7VaFbRx|^69A2X-M|%c1}cE#?r{S zkth?njhx*GKs(*`kuwUkqBa6I$Qg}t(UkzwqrpRr6hNJrdZ3M*uusm|d;omFUpeFJ z$eEx7z)NB&aF?7(?c_{Geo8KIiJaY0J{5eV*#VSG$9wv1a%MD;vj^JEY$0dQ)xZsM z_S#3z-Vr3FIwEPk>c-#pRCK<{Bwh+WM5XY)`9nld@?*aR-h&@3mwYMx8>LbYp^b2neKewR2>lR# z2!B(Vt_PadY273aP3I5c6_w&*8HdCn`7-OxY(=O;n$4ebJ=bMrZBPCpE9-hMA-NZm z;d+*5Wz9_9o5kPdPbD)M%)(H9PL{uyo>|%T3=L&605O$c+4T$!a-XGy+IWeEDUf`LYz)-5EJnl7i$O#R^dHRC3lnS zv<5vBAB>a?MlxjdxJ_wWj}HrqE%8xB-hQEA(&-IpO{2z?1jP+gdB^^|qp*UXI=)Ze zzCD?(*}bMsTFuln&6w>yY>4LvTgSu(4U>N1!)Ao`o3wSqC*CDP+=q|cR2COhB7MiJ z)L&rs*9RyXS*a!3E`SLJmYcM5HAM{4)u&V&c!$B5? zK3K1FrNAudA3ktx<`JY-khws z&$uBCuGF=g-m~7XS+lwK;=10O*7Lih`tJ?(JtG3$T(5*N8vWoi*;kks$rvF7n+(M5 z#=42TC&l?N=n;B_5fL;xNqk~#Fia8*jv-NldFr1alorNE=oH2(Q6qG*bKEcszFN>L zqR)Y{El(Hq>MxC#?0V|(>j&Q3@@0^5P*uO;5k-^7MET!KSy9q`X|rNO(Vmj&9co{{ zg7mQ1^gqS+pFTQ!tRp5eb;fQ<9Fq|66#vEaBZ)nyFMe^`wgdJ3(u0On5BlO<)2KmX za>^R`o14!*-MfV`2grtJ%H>SYE*^nbU^M#BdTrl@bZF zPn@^^I%}DIofES_rHn0lVq&7+2!1D zK+iQDAZ~U*Cq*WLzhrc^!S><*)Jc#DX8W=Im|&y3*c5o3$$ldlD7R3Iz$*v_2Wr4_ zI-`+wj%lPo96D-{NigNCj3f{*7+g1RMlTuYF#0HX-jqr=R9$M~5g9~y%_4)gEE#K@TLhdqLgev0~fZ$Cqb#}TFn68SSnJVFe9 z-u3kgSAX|DxFlO6#aCZZjt&(VOHet`=QxK7yy#SpSlODuj&DLkJFW%?v(C^^)<2N# z^XM%gFtFo_i&g_ao2j8M1zLgHPRT(rJ2hA6pPs2H&UR{jHcFvPu-!TSCbnt$G`+j; z^Y8iSg9Kw<05<`djb^Rv3+#0AaPcKF6wAI4$a@9{GrtQQgko=!p=a=CD%$iC+H{Fi zkR3C%%VkXM@(~OX-^`}SZjrY@v&%y;D9)y^ywS}O%rZCdSN5LV?GLFr6ocPx7VLiB zgU=*~WjIMp0jLSB5cEyZHlarn)uS1w6)dD+ZX}2M&$;vcoRRsnfB$v%p#6dAdv>P> zGLF>!`_i547XEzmZ=bX<1DVw3f8KbBAIwNE&v@s=%s+(|6^8zG?v+b5=+__ zxpH|X8?N@3_DIZJ>LYjDALmdx+!zM*%Rqkz=!c+35(iYA5k@M=-zj%Pw{(IiT`DQ4 zq1=se#3m+5cBHi5Gct`|W#=y&)8ugToSV^Y`i<>xE?80!F_$l9nj1pQ%w&GE+F@bd z{`*&}Mo*qIik;dmv-sWbW0T3d&~%eK~#{mu2^zld+qAXgxKEMv7VmYMh-4pkP#i%V_Bsm+F`Fv z?;f2n?o{#9sokPe=U1*;TeWy-(Sr43Co$#w=1d_Ix?NDx#EwpxWL#YjH9=%G0~3~RHggBY02 zOeRR>*On>y)TENz+w&zJ?f(?yRtC8VD?nDQf1?pH4OgXVDYkWOG0=k+u)R^WylQ5kQXfcl*x@tA(uk% z`5O2Pghvx*n>fO%&VWpCTu8tO8iE8?T`akEd1yh1o%86mIkj*7HhoaP!Ohd>ROJ?- zv80(P3yb=GTHJc1X69Q#Jr*y{P6;w6re>|~6~OFyXT`dI9$_>e?mbb~D>1z?qI+`a zSlQsHrF_sw>z4nmqPhRmizcr5sH}H*R6}2v9%h2i6SBpGMS^G(z>Hu5l}ut1CY{{P zUlS+r;*gxs@IQ`n8p=j9)PD=_JzHb2#%IT~3cst&eOa{K!p~mv-Lw1`GiNe&Oykrm z3f}|Ft6Fa;h2){GTPd8nKaxg5d?37*pxdH)XayaH7C$m4f@6;l?#2X*k(X#!T9+-_ zzk9(-CNgQMr5uj$f*gp z41679w{+nf69)f!!kMvhWlnft=90zPN$i1FSM8s*BrbJkc~WRZvMfJpzOJVDo!{iV|- zbQE{_2GD}<+9=ZU7e?q2EzN)PWD9#nMD!G(-(d4{xisND$7yDN5i>F~+kd*e*$>X` zg%faYD4Lls3_tCC@H>3&X3_{g3o}yi{;&?^^s+Uf?(+N7Ef(o|xqGPb{yWlM zM!!%A8{%y=db1&tP_tJD-@(Jww zdPfj+^@BcJHe8SDtWSnf|3xRCa`|BexSN!MH0K1T13%K{rL{^w;5m2_N& zOJ!*&ls!?_LJo=)cyW`egtbLF15epGwb4T{o)R_waVbj@$MU~fOmAd!F&o}0nmKCJ zi1Oz@9zTHpzH88=>lWpmrL=DJQ=iu}@|4WU&-IV&**$FR)X_C>R>ms5H2T1yQI6-D z`CGS-yv|H!oL3olFZW>mn5~Tq`M1x1bnYWY%|yR-gm=DD(=@aH^xQ0F&-3%2ujn&) zd~8Pb>*X0f>S_Ilj7^9POCC3)Px@0y8Ii;J^&x(N&rF)m81}!>cJep=TYl$!S(wfz zEzo)TEYpk8T>kp}X@1}r@}7g9>p!V@fG|E-`^i?wmQWBObV5{tph7RmBiJGK2WAeQ z3yF!MG8!0Iqa?>>D&^0FS-X^wbk4;|v_ zB{4yWrrZ)7g1;2v4$&YAApiyhp=gp|5aC_L!9qwP<<~yFtGzvgnW2-(^at3BFFd_* z@`$IOnL6*zh8YhMd^AkZqLLBOxdk=+QjJdn!#v%}RJ<^0R5}~!w{3 zGpxX*EE&r(Gq!s9Ch)=i2X_3ecG#$nza|J5@$o-~vL1Xc{kv?MOS3U&g{74sEU8K< zgCdCGiJ&X=P*GwHf??N5|L$jzEBxciDi&8vul*Q(vEe0xW9mb_B$>1o)*US!-3ynK4% z(|`Ur!AGn0jsN7k1=HBg{M}O*(pf*BAZb8=k3*XA`C0xB6R`d;q;vl(2nC-21(|>c zH}DXL7sQa_eCTRk<1ffZoJcA$Dv4A1W9Y(}&Y?p%Cvz*lzdlO7K;`D9Iw&npjxpvG ze$M}q=&L!nEG#fCE+}m2L5*)Bqq;S`cL>wYOVgPkrCn;ZsY2x$e4nrKhbVmG`JkAH zhK_$WM8tOd7VoQ=UfkX}UeK}E!CN$V6Ikh#!@sf86|9LFouZSz9%JlT@JV~5Qopx8 zEFd~MAgq3`oBDd+bbeJ#Zof=pu-x|zX^Ld&mwktMdMEQBtxo z7oRc#T}s4zK-Ff~^&i}=iBIB_pNmTFIcH&rG9*`s&fi6Lzu9FKt<*sPlYZf$(H7X@y`b2cxct0PpREI4!Wyf&xzo-1m<{X z)Sh$IP>K3(eZrWrk$pS@J?3lN+5YaTB|=JhI8r?4somYx2L+20ptQ2;j$f_H07eiz z6X4?~4e|4FX2|6kEHe2Z<}0i6;p_d&Ldl0Z!fr<&UDgn~n(#mN27IHl?Dm{){Ho9# zcb(d^PUGRBULKbd!PJEI@eKCt$0c|v`?HlIA1b@lZdbV)_E2}f|E)!5mAhp7;B!d> z+7;GbL2)jP=nAi3GGO^!;Z^5c5@)WYA%acQ+N!5E&K)^EJtit+LC%J8DN!EUpZgEG znzvXcWxZ5M?UUA&4eygbJEmuks48~m_(4-7Ypv>F31oq$#QFLP+QqKfBkRw&2{ZCP z4JW)q+~eaWt`J2<)X9Z71^zASJYulVOUmD4qPA-+~=n8nAR6^9RR z9rbL!(~<6aujco4jLp#axcVYp&?!UMp2r97U-|B`eM!;GL1=}*e?D|8!k-r1mg8AIJHg`=7 ze{tuL@mFaDaf;qmm;jv)%>xmht0(hFv#y8UZ~+xd%n z{l#-CzsRY~5SyAkdj3O;`GQQ!Y`DMQZkBFQx!-T^Vnga~RY;^6=60E6z$!uU5O+NI zTs8*w&sW&Z5Pa1`(F(ThfiQT)_mgdIljGg{J0VPJ;r0i z*x{oXFZOxWW3>uArey z&!2FW2sYf}yF7%$F1@g6#f$uFZt6q1>HM+S+&uL>=!^O__Q7Uc0jPFUT#`iDJxmxGA2%bH^niknLYGJMAmZoY^6X7k@>_myi^o(K!zW!cF` zHXoWbYWYj4CSQfZZ|HcN3~^I7e_%NV;cI5l{vjDzMg4YqTP)tf&b?I?C=tiP-`7v- zXHiE;Gm6W1%^T6rk+L9u>fpiK5BN#ci~~c%yLZlI*y4SizS%V{k2X$3VT(%_Ok&|{ zi7*agP$$lxpkUS^j0pN=VHWdG8g?+#cRw|MMPOgEl{sL|UH8TASrZC#IaPF6+x+IMtEwyxeh{Y* zEn=LTroNr72@m;G=N#^ZF$l&i@@HME6hZWXur~kdz5MNRiND4n>lLG4%HQp#G3={{}Yow)Fr@Rl}#EQ?(M$d0Wrsf zwlRkV`yuRM2MNAi6c%;4DA7@LdVQs9n8hsDM+w=|-JJWJMQ1MXSKPD*@&+;9#ktXn zIckrS8M%9>miLGp{h`$=*pnf~h>r5}8=hzUF0glP-a#_K05eXNv%`b`Vzghw!UOF7 zVGe^}Ryuh)4xWUaH*8VLT{aEN2SLqrLHM4i);w}rvg0kWe6EkvPsu0gQ!PWjSUf9l zXY1t2%p{L>Te8QEMDt7T&kGEfzM10VCb-NDCdJ05@PFn1DmiRaj&ga?&UW2?K)blu zfOt-9*W*95Zoo2HTqQi@2PrOf5>woMXbR_-d7I1%{wV*pH)m4tv*jw&;@?Kh%zIhN zq%j(mTImcLE4;rX!+VHlkLdKR1BMNk;TvpiaG>Ppc0+KW^oYjkaPgb!t7uP_6!gf9 zR;t7fr26`{r%KlPxhHUX!I^dHJZ#Wj@Soll2Y@MbK-6THme)AZar{v`hwO_+bTzO#FN(Kd|f&2M)0v=6U3b|9yYQGBNgb#^OSW4v}| zDE~L6*+0`h0v=43=*j%RkL9%CCY|WNmN4J2{&C)N(b3Biy!ly7fk_u`)VX}{LVk9~ zsswL0R+K;Z{~G)!xa2QP0R(3MItc{fyVOtT??m53*>~#W*ZT+XOFVu1u@mwV`IAX` z?rN0~6!7Dm>ALcTKh4ZDR(Uh!Otx;u*1WOMjJl3Ze63Ssm3M}iR%R{xVzNRi2szqE z*YOssavBR<0v3I(G!XL?pOmmJ5_Yc{7z%79I)u#xY^7uIBMtO#ALsC9dH&o-t%^9k zq~7V%A!V}uIy~Q-_38M{q0>r_9QcTN%dXVl?>BSwAJF$Ie49$ew<+=a1^k&nPJFPb zS^QjPc~%yJ{{;LAb;}J2{bPh6t0%sBh!aHos*A5{HZ+7RL8Wr$qS%M(Wd#Xj|s62A?em9V?+kWxE74D)@42zfXMz|?hpPkhv0G|ALy zygm89xfR9wstX24d=)C@vcfAlDB_2k@NWqZZbl0FeW5KnMN~lb6-8NwC-Tq;MF5a#@dE8Y#ElxeE2^9{qx<1 zN;^t)3Q2E6$M97f*PVEO?8@}sL-;I`a4JQAMhWQIWq%`GKKgK?Mert&n60k6@%o_X+%ndhPyhBo+bqfFJi~L`aO_; ze|qc5`llJg=@+L6eUI;k?W^~VLmRgY>zO`y)yQFG#cn;<>yb2TiH8Tu%#}&nSuUu_|oy8B;e?57eSq1kFeO2NM`s?yL4vd^4i5G z4podx=-8V%yy;A-LTOpU#`atg8ne@zx1}B5wBhWj#%JfxI+FD9#Kv!|jQ8rXwT1%z zo*;8Hd{cH^+}n6u##Say*A3c6otAw`%c#HYt97W z$R%c90-r0DOU_XWWefWR!kmY#6FMnw-U(``(_(MTr3_swTo^xLD^}c&MGkWHj8YsT zoXZe4_z)Y4zDQJ4c}9lQ!>eN0(8>u7b4CRm(e%~)HgWB14KMCk@mfYw;iz8YD!4Ya0#e~Hf^QG<4 zy|cSTX7#%FxzMP$I-Tt^SgT;N4DDA_ec*W62UGYwX0h0w5P@pt;`A2A4`*-iBAy=- zw=aZqD<)y%$}J&~S=>8HY_k{Bzj*QR>_JIkVJUsPCvW%AKgVP}YIX9`vWX$l#bL?G zVfk7sW0H&v*2T)Q44v}Nfcz0}J>0jDxVgR(cCNI=^?zqD8mM{{^kJt$&?RvzTbfZa zHe+}Gg9b0}XhZJYS%GbyM!jNOq+uKr$8?KIuddH5Si0g>A4U}&7*PNruyH}mi0Z3x zN}XK7h(j?(7zi(>x8Z&VBMS|WWwYGfv6Z?)!)p1bd+W`@#*%A(`hs8he;2>Pr~8M@ z!63jevA$Q-f$w{EQ;dy3`>_h&Sbet8T01>h=PwsU^(bvtlq$fb$w*@}hUyh;mf^eaJ{>)4 zaKTO=&f>#Q%=74!n{*QTiErwi<1Cnf|81V3Kab5atEOv~X_vnr;{3>}7G{}?>3^SN zLE1-i>=9>t8?O*%SeJdj3H$EtI#&qaN?jj~-2TP2NN&QVw(&nVtbYH@>W0^oi=S^P zic1>QysIdRIrl#QBV#@N!KS9?HXZ)3bmh9?=RO|YxV_ZX20vCh2>lL5^wH_RamG$? zU#@7pYq(uoNrB=3V#h*sCql7@{=9$wV3U`jeot=R%YmNRI-9#9!cfS>E!zKf{lbI2 zi&nfo);40<`jWn)Zx4y+&DVyh{M~xVWW87z8OhB!rO8W%!CA9rQ{%~J7j4Fw4VYRsAlqr{RkX6=5I?q)A!gAQ_~FxxGbv%nsryCUbpCGa zA||qG#Mpw~hjwtH&YEWvS$}2)q9tqPNntv=UDqa#5k{BP7sbyDBf0lnaLkVSuJ7mWS z8sh~6`SZ{ILf|FDBT_{ zZz#+iInu%Oviony8Xg%x_L*o-W(w<9xvWoWdb)%654YKdMnyQohYX3(8y(q0I(hz7 z7AT&^6?qO4q6Oh|R-DSA!&ZM>EXFd9{WQA!p7EGbShj5` z+doFOdiwJ?j@t3+Ul^xa*dh?)Ghr?VU@mt>XO9JDofBL15TeFNC-E1Cy>&9Dhre+O z(>)+;T5WERNKD&Q{4u`!Zb|>s%u^GLN=Un-`^;|fm7^9jwJuB2;U+x0+UzIU3LX7V z`vF)3S{^wDX}`6}{7*`&Rmq<>M(B!ahB7ziwSVnBVR>wJsbna#rXwdLguR>Q?ZyZ; zKGC;h6YI3AhYJ?Jvn|=LXe&u1SzfMHQCH}bzYyp=egk7n5+`XP|4Dcp5UphV`o@2 z`;SB)7iUbWr+de1tbCG^6BuPuy!<-$vrbMuRwAqFk@P&?R>wZ%N#u_ z%knCkCTb2cet}8$LU=PtoF}9CAkdjEx`ev!XBcg%3jb{=_bfJ6`}3|)XS!5)kxbTJ zuQ`i$S}D~|Gt_UZqKj_*4nE~v;es5G)JY_P;T(Z^kM z>r9fS;}urvR6ZJW1ii)J%LFDn*Y(1jeYmg}lsZXL9MlmRq-G0$-JP1?kzi!s4pMg< zx^tvwyf@RxSJ`}x5^F}v9%dNlV{HFRQO|c=eJAp3qnXCNez8H`7ehwgv;F&YFkd< zDdkM?kgb6pdX9Z&`oJMSEwNg|Q>G3adh;mM755wX;mj$i7BRU6qIe=kc6p{4;WmIl z6V06JI@-brR~%fI9VEMOn;`KP-f)n#L`AhDND$VU8ztp9!yoKg^+D@Y{;nhY z&(dOKJpC?cAX38(gjmA9naQvPY$>vQK+*BnlpQ!-gtbN5@*wc4H)7_j@G zA9F^ZaLR+f&e)XeR=s(A-9|NI=f9UFWLAnR@V?UaO~T^)SIH<3t!pu^0$({;|6i0< zVAllS1v}~d;JjfHf%Mg&8PV~f>82`S@iT$sHVEpNFGuZeRcRR79f#_Wu z0F1vu_Vug%`P7()xz(D?YQYWr}oHth=(o3 zgXW?g5p0PhJUyLVoSyzitn29-lMVa{NeuQD(?z-9tYoJmiQ5|ZEvyDH3gRZU82@$d zcXUn)K^CrE1>svC^iQl{NR-5UT)k!H$Uc3;>^aI%dr11E1=ZCHKbgI?YGh8ozJB4} z6BkZw7>MT`&PB|)l{ItrC5A!5ZMo@K-Cl%U8E zjv5*aErzY_nu@T|;{KfAS&<{##Mkh*_+PN8+`wS(pIIKqZ+^h@&oYx3;+aYOPp6k0 zSy+4j@VrTxYK>8gb6R;X>=@YRbV~OjYb^j(%y}J0X$%MkV)&^)DXU zw{*>rw3rw+ga5X+cw+yg0ddjn`P9&eF_UnKZ(&xLM|gHjVw88fJv@J4Oz6Pw)%^90 z$(qPnvhetkQ9To4as=746!qYy zzT{|>R_Es!RS}sH~|C?{;O8Am!txkbFYs$ksYp^R%W{I%*y)@Cs z&(qh})7P*3Wrsb~B5~ud&#UGC>?ZjibKwj3(qWmA{Zja@AoL)ibEiL6Co_hIwtM05 zs59{Ez(8hSXec&0|F3s5q)+H&5y6f9H_dbtR~`xR37Dp?6JiLKg&oX<*f`fPx|R-| zUz6c3TncO7Y69s4koNVYNl2 zQb%;xNPV^Zcl{EcN(f&1(f_Q)8Ofm$AL7%I`yswf<)LGvq|zux>#k;-lwL+jbW+bL zjol+BOqkGPvXS|7RS4(LzXhGaHwsyS{aDsc zZtgQ-f(pg7G&Yd^TGoNIS*|ppuhLTHnCz}V>dh? zf2NleXNEyHo*ymMAjXzUW{a{4=4{l1cC7rfMh`n6@#5h}>6eJNBO~PCe{t2f}{-=Ct zwvR34cz;+Nb0{Fl2a()zZ-Ph>9 zt=-wH8~<@cZ(qI6W2%pQz`|2w6hSh@>k^s#{wH3>5VpS zwJxo|T?xKQk|?ed#k&&FS61mVl3nH z_|=Jri^%)?#p@B%aC3rTgqsumKOWwk5bTw()>z?|2ED{C9l5cmWW|GP2q(%Pp6YZ6mP<60 zIw9^8Zzu>#k>C)|nTsDgg%|(<-{a@Z#Ut;+H(=C}$gdW+C&+!g-Fj**{MPQAMYzdu zJVd<7P%e$lln!^DKyStY^le=S(6`|L`d;DudHde{Snb=c70N0`Pz0A+kQaY|d%z}LRN#b3CAV>gmr+Lg#S31VSO&kxwa9}*7 z#~#Y}@$|>X!_7??4_EoN$HvJ`F38=Le(n(+cDqPF!bM-w)J6Y^^!FrHV!8@W<};DL zt9+Yeo|uj=?(8vtm_(Kqj3SW#WdeVeS@4v2T=(Rg%pXkPzWev)3#WF)xgnf06vrUhH3l-z zhq8M-{XLoXv2PRoTQmuCfAhKPph0>^jB-$-_|?!I6z*keg85#!52Kp|4H` z0l$e(l2#0B+q!Z@wE;s-u?3ZNBa1TWG0o8X%8GM}My{{O*Le5WJG~g|HDTYr&kk>z zz4XaxWIq|Xed-)J*0iUr-wY@)yv<@#Bh>nAMN z&q3}A>Syp=%@Yu}GdUEYcS+7;f)j`N8$7zJ8H7#AoUTR>%;>Ww_~^t8$&>j6HBUgM z&&AcL?M>q#2TT}lmjUMDwCHt~0rV<~vL*m6EYH+!qvg|Tr?164pnd%lVxS6;WQGp0 z$p&+E-HgdWG)K-2TG+OM{&cwqz1eTv8eC(rn=mgc5;+Cd_$LXV4CJ++#@4>7)7q=A zA6Ko}G!3pjAFp2fX&PK(e%-Rhz?YQW|5y3`A^f>^*N=;?c>VTkaF)zt_vhnJh;01r zzrgiYc7J~TEMA8*Cj0hJ;&IJJ&{)!N2k>}2#-4>Jd|w&qh2RM_K_D7lh%Z1GIe6+a zQDv~2S;y&bM~=|nh|7^jM&%y=Nzw(mT;B0w)S1Ko)@p)XJ|jb(C66vzUsqIAvuQ(Z z0Xg^%j(z8S((@%EytYaVch@eQlM>`NYn>SGrdvpVqa`gzf1BBS_Hx_o+0DvaAzujj z6107GzJLsp*Zw+NoBr(jF$wgpF0LP!w5sd4_I&&a39M4fc)UNqe$wVX_)hrsv-r+| zzn^vR1wX(Xuz`J{2Eo=2R{R2>c*F9^I;gm@G%2aHEHSZ6a8Rm-sRMq->ykF9q$DY^ zw3K>*bATG)r$o2{k79c%O1v&D1}v#Spo71mDA{?A8wNe+;DBZ4Nv5d08J0RRZRDoh z%^yJa#Ps&fxm!OtR7NM&jD+Ngnf=BmFpOrWcMG& z?tff@`vYHMegx)V-eV4jO;#obLQr>QIhp@wIUHJzlEYyhY@fuz=ga8Fd2#yBLaj8e z14v@cTJ3tc4m=4wdrH>TxlB%g>s(f!5`R>UH(SP^wi*AZW&CMnJZ+b2kNN$tYmdqF zw6nZh<^I<-z%@t@*4wgk8a@L($5r=lXX{_VughlyACGzfAFt?QNPjz%FMRw7g&w>= z(+~LgGZNSJ_;_3&KK@KM_rG965AqKme?gX;xSms)?hG*`p#Orbo8wvYfEKAl2eMAM zPv$E&9`p~b!#22%@xC9WslZP$-2bh3MU_+vp6F^stvU_RTX-G?NIa%ttHqr()$lw^ zaJ44A(h+(+d6cETK5wA=)tRr-7DGo7rn;7>a$x&{_FTd9VCi*3M>Da>f|Yqk$9N~2 z&FPeNuHrNe@(w>E)V!n9BJc3=r)|a~@9^=bRcooXXU@p_G`=hK8FWULn`OXjSeLBa z|GLK6!fTkTtK9#(1n_(c{VF@^f~?2$`{TRi^jxs=f@TpL50((T!xPf)Oc!POu#DGw z^Xpb#(=1~1<>OB)yoUL+8k{d5Z`muLyDnn9$;Vsf%f=&b^6_WHE1Z7wK2~2GiMh}~ z&yUh)@_ga`jMw=1Pn7Y%n=2Xpn8%Csb2}dLNu_bR7Px;O`FbOH40sWF6Kj7)qA$m2 z=YH$D8d$dXkTdP-e?evL@+wP(lGz*}2tDswA-q+u-+K2d;VlNk7N``aE6v?i3yU*> zzh|o|hG)-K)eFytUv_N3nqgrNiKL&yk%nj^a5kLBb%E7D>wtM4y3GexEe0gSLfHl; zeHrg5Klpir;dz!LO!n&awDs{bs0ooG!N24438;qn%!hex_J**B?QK5(6!!t#{sYG6v%Ss7pAth=<8g2E@u%hS|AO%)jMw@2 z(_#o8Pup1ywle;@%%d5!o#i%1I^g-L6RwM}2l-wFdhmSb_dmmY4`3I;i=mKj2Jc3G zCn_)mIs2J*N_y@((-}wwA5EoZA@F=OL*u*GDs3>CZG6+6*`Fu4q^4;W-m#wB9D4UE zb6)d(^9%c$Z%u$)^L_K3I~Af!m}e!PV)@(#(57L}t93wiEZXXn1r-i`)WGnT{BFJj zI<2;NO3C{+A5gN+g@!Itz-e};*J8;EPf~KyyUPym=-1sVL|%c~&QF<~10O4sbN8W~ z#yoam6v}CGgJ0*ih(j63QLK-T1TO%SqZ;@J?vr8OCt?11q(eV`9d$>L11K*Gfaf3> zBl8^Q)uG$KlDhkUD=%Fr;(6&5P$|34OXqt>TEuiJ$drZkI4(ZU&n;m19=fqGKY)p0 z*F(rU91rux8v97htcB}8O7|)2Az*&HGX6&q&K>#wZ?p4;kH4gaY&Kj!FbquWI=}xV z=_Si}_5IIi=F(w&yzq|d{%53CItj-Mt z+!?IK0NCi|=H%w}k{uKP8Rw0c>5NX80HnFi&CA`(ZGo^v4Gv&7o7rW0okq(r0gN}; z8i9txc_S6}Oa|06t4NLTG$DCC7H3R%z$bK~L<2zyp}a ztBn6qYE|BytV8he7i{j2IupPD1+~88Imy+-~f|h0H-rB9rk7_z?_v1#M&Y0X{}SGQ-DMGq7KzxrdA6 z2N(PdAF9y{J_rmr%g_tP9+*DYikC5U^oAk1QjLdG*JuVCcm*xITacT_U`>DzF{;Y5 zQq+=>mop*LDdfru0@KqW^E|{;JZ38jpT@$Vu1Xdr*ww`d*N6+N4~p!jb^(?Y-#_}M z*}0tx7to&LK4{cwud{QT`v^`cIx`!O=Qba2(NWoW)KU5P)3P6l-Jj`-eEfOYAIt8q zb+C*-kM<3or?)TZOi*W^4lz)cJ*%~VAHdGImoSb7g9q^LWyB?&slgnS{AzCnDWdvh zlJLfzBRHWc>p6_Xun}KkBqvURkVvwi2?Z#D8*>K_-25z5>;2L8=Ho9&YuNoG zV6jAI5ApFA#7)Y0@i|5hoDWEkc!kr0^%IO9NQGh7)#LI0eEbQqgN;vu@&94>=i^U^ zyZHUV_lcMe@_2{&4yQT&klTUv8Igbvhxh+UJglO}dVjFtyS)De>-{x|!w`wt|15sD z+j4)brHDi%Ja&KX*GBuPgy|t{Joo~5oCx>IB6cqF@t36E;d|_yWA}&AR-6aLY5<<< zg!dr(0oVqy$9*8fAXfHdC-evU3^)OXbb$e3{uzyi5H%14`5Rmkyew!CNF&fL;9S9i zvvjfNsbx}M^*JC#19_#r&3e$Cz5lO*Oka}jmPeA zGh*ycw!Oh$!hNoT~XQKK_*AhhcFel!JWyX`B0_9OUCq zE4~9Z9%I>j{5gnMWx{j${V~?S$Dfn^jVL!)GP%jepVtH_yf2Moa+8lgulVJ_m%-0v zKK?r7z~a2XK9bL6KK{A}PES5x-FJ-Fa@abY(8eqG*Zhm^l_q{&1DXkr2j2XGjfd~U zdY-^|7`s3EIq@7H#;?ogI2+IGFFyXPJRWtk2)3sIRRZpFTx#X_0U6N1_B8m$@w(ze z!SU=qeEb=xFJ{kW@tJg=D0IS*OE`d8#?$3j*V|CoYHhQ6p z5`H+(;D4G|L7t^K6r%;e_Olw!k1rc84Nth`$*T|pmGhOr+!3w#NwAok_mv+1({7ttCFMcXn*7sk(T;x^mN9Asm?x zOL`sV80L`N#S8&)Qk_U52X(r3} zs4>dj*XNn;*+6riKC?f&U^|WK{PqR3bODQV8sJEV*{@4fMg-IV^7uAi3V7uI*{Jpac!0c?uim%}ca$J$OC_Cta^Z*Pn>Sm({2cQ@{Tk+>&xKUeX_Ct+W8iBy5I zZkUYWsl{_2&)M6Tw7=KX;J?=Ir6;FW{T)LH!deNP%<)ynsx?NykmA2Hn8SLT;%r ziskYM>6{D)kr5ZtQx}+*J>3R~!-CT>vFTL?4dKM0Ax71Yr_*`{Oi74U<8tUNupJ3+ zZ+aI%BINT0aY~iA1}wZb3O>g<6aeM+xTW1m8ry^+z9~(a+9(y6X_u1aF5srYUC5HI zpia?#fqi0;A2Gy|fs8sAOFzRZKuifyBsTbYLoxM&xgDg}%_Yw)-Soniy(Ajk3Oi5t z&hbkziEq59*JymFL7SFs^xEQQUt0Pmq=dALd+hlML&#q<++BxPe?pEFIHtM;-}*k- zB|)eaJfB^=^f{LvD6)Bs2r*CsaTi;vYGc$ zxY!LCir|oL{z{w(`n3hs7Yn=i8NoTv;yh%@DdF-tqCW1RYYAjRPn zn>4R^T3cM!sJb0>dA;}2|Mc3sWaaBGj~lTgw|f1GimZ=!53Cn_Ut6}QS5*J%w3^lt zS@8fFGb$@?xYRE=vU>EQj{}}Md1Twp#dFT=ny_losLgL)_nSNp_dc9?GInhYwB!LY zF{cNiQZQE_%rlKK8Pll2qstaj{dP6FTU#4aqD!0pK|B$#c4cg2T3STxDg>;hH!jsx z`lVz^4F?h0b`iLIIyxGrz!4z0r^c@loYusr5CoKL?E5*qUTutL(5>%6JR*r~Cu>^4 zb}?csN5M*jR7j2p$Z}Fx-DNQ3gyF6*dU5?g(|Y(Qy+(g|`;dp!pZ?L@vT4h@L}x>= zue;}<*Dn&kqpzLsSk&tW1XBD_c$$89>FWz8h?f_+^hEZoX&XX%lC?(v#k;=vh|Z!L zS7&CdmUT&K70{xU&M0l6A6+qOOA zKC*S_)};-@8+X#wusokpoxs|tuC}z~@S>J}X^9%ZZF~Mt|HIQaH`L{oEu6fU{3-l5 z%Z*{>*`T)F+&pB{#0m7Tn_K1-qglhxSM6gUTOo34iGFk&;FC3Y2KeLY%V3P;rBzHY5hw2ztB=g{`_{^!!0A=w9su?>1-3COZ<;3<)irze*^VyGL8u)ji76{Rnc;&TSXcl-0taLH$m(`Ei zz#8}Mm9g%5GL_DKbh-G93evcv;Tq`=YXv8{@Fd(DvwnSe2)Bz$RoUF(2PPO@m_n%l zMZLoc-lY-!YOk&KF<(B!PFsFRkYCn1AC7s=MR7# z2zh;$7)?}nn8*AjS?Z|SQD6%ubXVBp+L7-8gq8(k>)v6H#Xr`y%!-UFvtVzTpXdtt z7~ds$*&rTeJEv~qPK@jBG$Hgv-U%J)1gd?O>D((!lK3-%gsJ9Y>MksW^Kk|K$%MTI z9tjKoD4ug3Hc{~oM$nO6G7Yb@kca}K^oCyl28)-x&e+47M?w&aNN6Mf1ojY;1hm?eC?2u!i8l#HvgXLZTL%uCcljX#N6C5#S8TCERgwgZ9r@Wt51_B?_D?!3?5PG>vkQqr z;zB^Ur^ETr;~gv%f+v6~y1)c!B?neM!9(3mF6 z4zQZbf5_*Pv8W)ZfA<^@egt4>$BOuN7c45;hOuivd=sDIV!gYFPRC?Kqr$v>1xMSD z<#E~}Y3l@Lu4+Y%(F=Q0DEazIgaom)KXCgURlpmr;+l>*PS8dV0kw%ep!OBAdrM}< zRywAb7C(|@+KKiLJo}*LF!xqPyZKB9*B5}yMy zb?f$9fWB7xSxBTBTgWe5PdZiS3A%M6`ZIyUSdoFekLBHq`(182qpYo*$O8Q?EpaeY zrp~h>iLQ^WC=lj(JFSb0NS?E0KmF<5*ABl+{Kk(<4Na_S^(Boi`okUX)0=I>5J!F3 zh%tTo)2VWLh-S+?Pv3|Rz^%h8z_ZtM;4iIRjYv6T2^?4(sR=CQ0C zsB_2lrBgKUYdDJ9 z&|xt~V_v16#HRc8F>mZyzn255)vOKmMB*7rp?JC4;8S7#X-r!+0<3M{9qr}hEEsO} zL(oE@f*cQum(kV+SAe?-X@~!5mNPpBVg%gVsl;m8Yp~?9$n1c;4EBP>dtzJjVGPkM z?*cHsD}O}gJpjme;gV1lfH3-buJIo5*E0Hnr{R=RW}p&PKsSp+s=Y((njD41uOQ2H znRm>fKrPOpdxVhFRH@E=bP`?aoP>g?iDVrP^ zb#NNvADju)kE)>MUrNnrcvKB7|6zIWuG)5he*1?F%zWc$JD7RB4b1!}7MS^PyCxqQ zcR-tGww{7DFC#(7JjE=}3@GpqK`Rwh5G>C}3!m{F+O1f>05gP|9?*Tn=X~5f{F3kc z$1_tWJ-TM#Gw<)1M1QJx^wf9-__=zPZ+c`Kz zeVaaw_KMGcd(sYiC8k~G1Jb)#qOyS%w75O|Eo_hc+P#Ds{l za6ekivT?)cVyYRu3m{ew2QXsg!vL=O3jfx7*NoWkz_8IntDl{h+)`iEGOV!7Llhki zfqp)D17>d=HgRZrf1f2^_bwW1*xX!Iw{3P~xzSG_-`E%z8lN;MC@3zB z8uRmWD^^YH6YH-DNWQ-CM_b`-2rDtejCe^l1=-qn) zUth>U!}uw9?yNh2zi{+Rcp{)NhE%(P;hF-FrF2$l}ZpS+vHP zVJ$kvm#qRj(q0tap}~OBEAz?w9+)mnO)4x-nbo&q?(_rVgzj1m#JlOL2kqKcxu_s1 zxnNZDynSQZ6h0Is(9h$rI~E6fmtpv%?2&A8DfuwDty5-q5qZDm zK4HKp>vA=lI4PO(&A$+rHNdH=-i1RGcD6(-2mDZGn2Ag zqUt^G+??TDP;8(2uuTz)j;8rwa+a4FJlX$F(&e9d$E}qj-_`FlEx8 zA6`mv1D^@g7G#Zx=S{)B0O?~TU*iZGnkfemA{FdN!$ceG$jnr=z9xyc7KrqqV?3P`*$sI_&_jl_UnA+=)D4$)qT?u%V)I(=#-Ee{Sx6a_*T;l@$$zn1Tg#W`d56zGKkP zP^*#8RmP6!DfBUf$(*Vj{2HY4KCBodakgt>raKw!Zq|_MP5_h-kg1m_Mq% zX?ESvr{166?5SN-UNa**qpC15x!}>syC$_JgbP1?{N!sB7pz@>R=5EO^;z*5;mLFR z&s#dktUoYy$?tFdJfMLLYEGJu1O>DVX?9`U0C3j7|C+e5CU@&?d_9*Q8Qd1ISv%ygjIUS6&qEW?7At^_wW0 zWr5#GrAJ?;w;!6jKxvyirftH(xpVrr?$0gmMINPB&L4DvRvuGB-Rb@#OYggUYuARU zGalp}liSNn?ptu^(9#F=VZtV5ajqI3+QrvJp$pDA#AyS=4{`~?ISyO|`2dL|%t&;& zQ*j&H$w8^~*N5osmyg~)Lif9eic|GzE(g!kE9B8$#ku=i`_Gwsa6;RdKo8LT^5aLP zKlt5-UANvQX$Bzx`i0T*3on|dhv^?!dg#!C`%22&HM#NeIlwD^kEY>4G zUwJ&x1^jC{^1!_<(<-)Py5>dRN8cnHBNC!k?W!5H>Vew!?AQ_0TIQWxvwrThLv({z zr0|h2WlE4Yoe=5z^y&?h=JnIG#AdZmEy`T9nw>*O&mOjV zacs+tvBeQ&BYpF}$UN6fU*V%jaj}mVT}gi!BP*Kkl+@LE`g!=YCJnBr**34fsHeYI z+`!$Lkz|K=&=kUAIjyk21kFTFYaF&D!mjCQGTaaJlV*EO)}FiSvkogN35I|AWy{Uf z(|N!3ym&ecHs6_=PJP$MA4X@VUlxVF>T=)p(qiEEbxZA0T&pUG9Q(eIQ;&ktH zubA|u^eG~o_%}Ipn11HgBO*0BEHA6sC2Q{3sUNMqkE}F0N9zjcqBW`c^tx`!TBHT^ z0458V-&c8s7E)lHFr)8mFX%?brU^X7D9t^yG{n<0fqxB#QB8KMndft0HI5hW*d% zF2$C_g}^`gM5ToD;tn9=>F)5kt!a%_!87iN%DqQPah%>5;h{%3Zsu1piC4j|;>YrF zJT!pws$pObvQp#={GApeH`?}u58_q&>uYb&3r!*M%>A7^aAXrnJ`|d?VDgq-tDX}Y z>CFopQt4kumqZv728(+J`(XcqbB+0xwC|eYrWNMVvGX2cyg?jppC|n_vkJw+nm-j4MTYXf0hO*f0Fe-}ngV8VGdj1H{IHoxQ zy$5^2PYkD9OjZ@2jkZ7!z zxaV%5HsvoWy}Gd$X3$#lj+2CUiT!Y@#dYwGUBK&HWIIpp zA?3j=HWg;wKpdtk<6kMQ6W1y8qAQg!m$h36nQ!X{u9627mytwI+gMq9;|U}zcViy@6v4)JKWx(+OgoCx{>000)Es< z{~P>xuM^ct%6sdQAD7*6o_FU((*K@j%J@-pL7pdMec$uGLp>7$^k8hmYh*enx6f^^ zTS}QQ-le&4#~DA2{g3Vv4ZHiid9A0aLsEC~GS{G)c@31M1`h6jo!!5`{9N$zAw4jj z*WH6Qi}#nYtuR(Kj*TBIk1tV;H$lt|$43c(VdZcWz6Ui7f-~HYeNP()zsK*v@1-oL zYkGy+So|cQx{ny02PK)@qGjXWiA1X3%KX>Tu1GXS!T-@g`ey09`h>GKdvnT%EPXfI=`$Gx|fmo0D9bXj->Gjb5r4D1liONOWJxz+p+ zdi@VdyLm__d&)pU4A<|W;k*-=Dkk1^9<#`bn2jRcJ_R@z!^E?Yvop}4h2e+7%w%^~ zltObPSbCtk+4PZ2gPyqMvX&rfXOJ3 zL3mwNr(2*ag7N+2>y2bN@;}rYVXtnb4)nSPq6Emdv|YRoc8O94YQavy@s>K%DCkQF zs##=?G{1-U$AOxhN9_$bez<0Zm@6-Dh}V za_v5o#dxMWI5^D$yVegP1t2}G{w=Ft3-fzT5%wwPQ2NnzcDd86?mM)0xUfK}ExK)-HBSuOiJ0OAZuh_2Z;E)_&TIw z`tiAU=yOAZnXjWEr=e{KnQ}JFw0q*_ox6^T0N6~gy`4^Et`6R5IK1m9;hc0I z>5cDPbDB&?`N(w2U*Pw^-S~TP{_TG-o;cy)gS>+0I;)T5=lXGNi|SlQUg78ZanSL& zoCl0nHvU1Gw@%38qd=bG_#^UlS&lNjqeZ4qCwwGve*~k8)s-S$a9zQq!to4~3g@E} zE-L2&n+Mjp^6?kNPb}-DV|A<1{65md3jN|VcK<5*{;Kip{(SsJWqnbnV>m#3{6!h# z3r+>$FuOn3y+4w1gWiSfRqXy8H|Qe;s|Bv_VfW|bFUsSu!u2c_&d@~#$B60bxISE0 zSFg`?c7Lv`Th<51v-|V$7nSo2=)cbH&&OX>;UVm0^kb|A*MB@;9}wmuyZ=CWeKyJO z_mXBWyFVX)5%@`|e-+vN`S^?0nt7YL;g78E%cgGlBNaU>+5J)Xhxcp6X8``T)-hjH z>XOa-)HU;f_0p5knPJ{%Q#1dg_#CGnFalIH@K($*7_Y8@|52&6qnn^UgU9(iG!m4T za!))>2c+L^soq>2vEAe!1z5x`xFS!v|+3SFJhSvv`)5 zQ&Hu#bz3LSo%`@#HTMV+}2dPU`@XP#DiXVV`r&g%o(@-=+d?^N%5wbK4l|4 zVjilB2%j~ud2ne_uYjIs_{<=uUKOiB_sPN7j0P))yP{nV z8iAgQq8(lRmZTV#qa;?-OV@8t9{%vyEh$-JGaG8-({sk}))x#(POlj~pa(XGuh#|>&OEt>rKqP8NU4=)|MWKw1S$gt=rQ&O2*_>RijyyBeL7`?Awud^XF zH5nzVTAxbr9@5C<29s-8Ck>VP@ZK#pFUmEh?*YyeyAJvuo=K3$*9YE9=PX3_X1a;T z@`K0->8_ac!%i?wpQ=jw*UGAd9<#li4AILTc(rpjKW6fiLCD@GziN5r%r^J{8+M8O?W zeFnv5wD*~Gp>1<^j*{l{O{a$8egzxJ7@|f>q?>zBfQIg^nE!)0aF?VNn#Td(5wi+> zh-4E>1K$}U*%}zlhHy*`i(+fdN@9S)cs7`{g5FQ0HA@a|m^6E6&9w6ao(X!@DgCX* zyGU(it=JM$8XHc(tBTn)ysmZklo|I+-`=D@?)vHJ;WgIh+N zwrl^Gkf!X}wG0b^pT+1aU}piW`%Q*H%g-@Yk)#WXA4$BVMB;qQCiz5p`f6r2HyA87|Cx{? z>ptr510J#b{c!8|+5GVP=nMJQGQaC=e)wFx&d(fsde4AfEwSfyO)q@UmR{h8FPKfr zF)B`J^7!)@_AO$5V16LZ4?=FJhnl|?13|9%V?>Hc6-B7P`NQoG6eO$zlPovHz^!eg zpO?i3^U0&I$W==ROAerBEH6B{2{Hka1+6jw<=I@ok;+7i)&99mVkx$P${(xpyV?__ znG3?~6`3ejV%8O)RQH66E_bd&Fi%lW0R3}o#dL_F2IE@?w2Od=eXgW6Ai```?M~neBj}81 zgR^)!NEXb^?Bb;90<}ZItg^^L?M^5sKp2layR)VkPX6-E+cj+y4+jK9jmKJwyuf7*1I?{LCnRmYuw2?59SxOL zH-pUYbX>@H*9xLU3e1bY`l_J1dV;aWhshqG7jUS9z{|s`C)pN?1bB2z#z37I$YfP3 ztUZS(@6Lf3>Kx!6yQKmknvX&Hm7z`~4KnYo8s9o(!;f*E&XTtuJ$K=Ymk$@ceeJ{< z61;rE#-gpkp(8!r_4LC*?PJH#%Ok`_#GIJj_trlf6JnlSnLgMUcAkE=0=l!2vQJ4d zF@Ew{$uAK%{6n|+8|%|kx6(BF1eck&B; z9PXXv=Oe{hpcq=xj{RnEzxtwv@%JrTbt)~Rx~S?=>`QA*reF5yuk@z<0*3(CcDDNX=UyvBZHCGPk1?!o{-Zr@Bp{*JAM1$08uh^tbx2@P-dx}VhC9zms zx~yp8*Yuh2v_ucXi}ZTg>t2rH$}da%xYOR|J~F;n67**g#|pkmp7GZaM+%6Od+fE2 z*U1_R`^A&#K&QnBuzw)Rq{vs)sNt0}`^-LJM&MLCs2 zo4jUMCiEze9t0G$=_X` z6xZyvySdy*NB4+Ok7!!m!EH>R@|n>c)cGa-pt-oTP=j7CMJ~o z>&qckALo2KLfi&=A80H#bLNf6Z2YheN>Y$&HrsGE?Y^t~Cj?dd2iU2EG|E3TVsU(8 zMxq}hIS)v#^;llpXrmpPmkJse_kfm}^JJnJUxxwn)C2Ad%ZC?qofQO-8>UQ8p4My0 z>cyQ0-@9?h*>}~cn6UE!-evkgV`O3JTL+8tx7D{n-K1$+%N!6A;<1DDmJj6Ect<;8 z@hoxoE+Xr-#$g1QVW_cA(;RCu#ZD>Cr2k;_fW{_l5&z=AyO=TXTO|j82ap*(vTY3X zC^0*|u;s|=bbachK|P-gc29Bh3JXX`UcDqSesFf~fB{X_Lm#{%tebbxTSOkXx(Ag39Er(_MN5Vl1RnIIXmK%x=b~EFmj0sm?@F}Co%R>0jB2CFg*R0$Z z;P|A$@Z{{pr_RwYaXvbq7pn&lw}z@@SFqZJ_X-n+pAQT?NB=YzzFScB?4));Np19t zr)@ymyB}<)8 zFSeI9o=?&)Ladd8V))3?#=m8y_@rj9{-re}AT7-pG2;S&vJg+~;znm1deR#J*z#b& zeTV@1x1eMBB+?^93Jmg$(H49i^d7Bvqh^S&`5ULSg!$$_mL{ZWXi6c60)^unVZ0&> z==U%k=yPbe9VJeKUMEJd8xoX^VmJq}la}o~N++~ks(C3acZIK%S6+ST5)Hf#OaktBnhe8qfvxR;WO5(PE2tn-7Z$iJB z@h=m7X9e~EdbFLINp6y%hTbgR+r-X5z`uS=J_8|w$_qtMaRq4r+dzS4QK3hIqJ(*4 zzB1l9=pN!*hF9$YTIhAiM%6p{{Jr0RE7i+bQqQZb=zgO;LJOIQ+;UaMBQL-V9@-P4 zyaL1E?#*&jnEwOL5}7XVE-1wudVggnqb!j@0LU^W?c}uKpsjL$ORvAhGNKL|ESV)8 zhYaQmb_q~`Bj929DatohQ)Zw8FaV7?dF9#_;1i2R-;5&t(Z6I{j+=(U7lfRaFDOx} za(N!Db_EprY?(B3)MHBh_43*trtpRkYbB7mk^YH*v?CY%IHj)g6)2H{nxC(>E2y*) zy7-$B6B^oiNf5a%JV8G|8SPf6K}Z6fJ{%Dtl!%gz9}G2k79o-sx05eS zlQf{bX<0)*#Tsd^7~GYEv! z2E%D>k5`59P~8ceqZ)+s!BKJkJzQOb2aU2T@qFH<#M9GK;u+Q>m>?u7`K6avyi@=M zp6`u1rESr@JbPu)`x7*;d)3KL7x~uYr+f+rRNvY1k^66cJ9$f7+sx7-!)Z3mu%;S zUb-r}6GTTT{U|iww_SnmiJ48DeWyKC-PUYg7q8byOK3HaJDV;H^;QsG+ylub?8HHS z&T^IT+yVF=8bDqO^{atT<{Hq7_FSAYD-G+1BHTGP8*=BUN3F zk;Ne7`FKlxHf0YuVK7{w|Ls(n^X8{|{X3KN$vykd9TWtKyVu&ciX&-BBoWbSxt#ANuEsP>&}3MC0i%I1lvufxgZBLb$Irvg=xw zk&3Gr=EM&AQ1~^JcA=67TciM{&3Y1|p%n;FCYj>ROUvmEyXJGL9xmSch+4svm{MP! z6t4^0)eJrAo}5-YrK;?}++D(#huZUdfUl~tEh8Z|Yvi|CZ-a9#RU1?PlEer`?x~?7fzJlku2Qv55ardK#1-wO`c-*4eDI3H1 zTJDbQXwLpFTfZFygg=#_X}+yCX(73iq^QEK|wNp(2AqrxiQSj<$eP0BE%iZS=MH0 z0JG97Ema43r(9-|BuX7XLU!$RXsX%u zi3u!J)QMkdi=U8e@2k7f8yQHj>!8JHf&9J%u+utt?q3|*!y`h7+s1a9 zA^n4y#H+X^Y;D+EJ}%W^DJgX8>XGJ4GeSqezAu1%pAP#E{9q~#4C1Bg?Z+4&MKY4j zCII}$Kj97)(?chJwtecl`qFXDIYlelHd^Yhl4{SsukWvK9OOH|_iwk)HM)2N+z!ck zJHOAGk!9I_`rP873vv@Il~~8#(r20U=dXSR0XvjQUDAfK5;~>8O0z|U_2ZxTDyw7$ z_aTYt>!xo1Y;tIThfCwR+kXQ(1~mdj@1Lzra!L=5GNvpTG;U+tilUt6ai#TtuIZEi zc20rGkuw~i$_)g&bt`$q>Pc068Y(9H> z<96#>58T z%=g=yd(+DH$;RGxc$naj3cY7yLGGq9kA#nn+y#^++$D;!9Kt|36i6faSO?|HB68I8xx&)X7(*m~bd8RDC)b7f>2=%BEyQNTYIk;Arv zH(o_+0^yJmQ-{pBgZLIA5dC%>dJ$=c0Ty!j)m1O9{$7_pmXdw@V%O{@4m07 zADUmTb)S@-+q!-$1S?4LFF}3B-@oO|sjWLE5AP8|pYIhIUGq-RNP3Z8Y!42Ptsdy- zXvot@DBt1iM_VDD#a*;I(Pl?8Ka<)l=!I5J6t@b1L`-e~xdhNjedg5uInq$lr*g{3 z(!Q1YvGhc6bkFKJgPp&gZ~okE^zzJ#p>$E2bN`*gt8)R~XAl$_m%oy>Wz3|a{N&8m zVQb=^5h}9Xon>3Vl_rsuhF(Jn7z4Lv_M2{a z^v*ab2wZ8iu~o2QZ-@_QBcNka{g`3Av9B;sVCjnGl6vOq@*)IS1X=hmjv1>>i5u~alf6y zzQfv|k*z88mIAsVJ5upHDgHVx`MT{b)$Ihj?ltAR>U0#WxhDhyx|)K0T-?%jO1 zS93YRc-0jcHk0}HAU8nqgaCuc!^_~C~! zh87b0q1BuBDcyt^Z|v>6dF7K)WseN>aRnC#MbQpptH)jL9Ul5L43x*P>8*EvU%F+e6pn3VDUC$%Ub$S5Tp=x2HDC+gKqq5sjvR zcsqFu?|VCW72pT0Q;0b`Rzg0+b$A7A4D33=^h5^KW?2C4{=w&A1|+bcY^-|ffn9}H z`uY^*`S-NooVp~qwnYZlHioh5ek|`KBDA(qxIV}$+lkiOV4mLa92o?c9Z3gIKk2yc zITDruQs$LqmDE)B1VV6)K#mAUfgbR_T6kVr2T({&nNexN zQG{-)Dr3*tK044{$k;W#uC=c3D$Ndl&l?Y1TVI5Q?0CO*tlvs0YBUl*ci170I|yYX zTWZqoZvRVB^DV5nv&3Xomnhu;y`ufF--D zo%lBNE~ah>0ZXMs|mspaHd4lfoFVGb_v{)KpI^|lHzG#9LK zg~;z6UMNXmyztCu65gfgAGMNBQNL31E52qrL;XsH0-R$RLkFHg@f={eS<-TtE1<@9 zc@8Tt8e|_@RBZZu1HyDTmhN&@_3)rN+nL4tk3h;v_%o;j@Y>+%<5rnx*y;UZtwI_- z!ODZVoT%3H1==u2gnOpIq1x^Fs;n^(g*7+8oJg~#FAtz}+rLqXr6|!8;k&!^Z#4H( zLMlijSY=YK_z1+d9SEYThJ_{(h~z2fCwBnLT`;*9Udr7acf^#O0DV*2QHvf8fGD3z1qbqh@HsSRrm37HL#JXxP22=(R{g^U4vpQ%qIXD!IM zyLW6kFnHbOLC=)D+Pq~Cgeu`o0-Hgz0&E6Le@KNf@Kl80wz@qN+YD)*Va!(Wlv}Kr zEJ%_JIznmPuz!4LD!k4^I zoDyVS=x=PVDtY%O0Y>^_uxpj+ z`DX=Tbd)KyoqkQvP6)?2G~E7&#w30RJ+>ihgmaV_CaCNlYg;e5YKvKy%qf5#1dVCv z*!@2QXam3BKW^yzumAF|BWK^5HUH$P1+(98Pm4|-(UK6E+WtPdcxdxe#GU@~)aFBf z-@ReegI7In$@-e4jhDrd@uIbgDF4lL8dwV$28Lqg{hycrJv% z;ng~rxYLChIoRt2qX%&OVeVfPBF%tkh659H0BJV;_XjRL(tInv@{Bx%O27y7Kg8{P zn`@%;sYuVSDtyy=xSU(N>QG7jj>l_FwC|(+@`~!n2Z!mu44DX$Rb>L z!0C>f16Ii~0F*S=Vt`jDh$8)zMaty3+L}s}T|f_|nf19(dcA+OQ%|%2~2`rqB3OV zg1KT~AHmGIGaD;=&>t-P| zR1eIcYhhrx9f#V$8fUUysskR)LtnbZ3!Mk9Gu|u&4l_oFYz?w^FK23j{86I*cn}cy zMkugMTB=kR9ap-ry!egBB&Urf>3>ZxDef`YS(2RAlP@;R*m!+(jJKi!M9?YqwoP!`3WyAqi*v3!gR7*AuayfXhamLKZgOC8u z97U8=7oeBio%D%0zD`cA-Z7)EZ=A7#Myz*|BW0byq2xdAxBReI*{P0`! zwIFvcyTIN;Y-dEA;*2iGm$}SPF+Xw~o=nW41e3LR@Zeo^liVr%n<1mA*<}5ohF-o- z5vJ;uV~Tozy~Ky-bIu-+=fm?kJ<1A)VLoT_JPTgh%W6&<*}8=sRB}1*PY%#vE+=oV z**TXJ_P7I`E8efU3Nc5RpY6WlyPCUnWouA&@h#@B^dUHf?C1*u)mb{Oh182*2H)8Lz300S|4Np$EK@TcbT=mwfMi zVq(jT&28-)3nT_he{+04gx_whWpYsNUkoUd=$C;oy)gsQCc{F(>ayfgz^)ZO-c+3{ zWY7;u3brUlFGO|4VX{)QVag+99W3)Tdc`XRQKM^XR+R@Xgu0jz|}BjE|J_1=_9l_Ja+QJszPw&yoRQe44C|4 z*^1GA9?Zw~Ah)RK_HXyl>(dj{C$`|aRsl`!AnPIfgMBJ@_(ews5dq2+0$Us8`~c7uNo*;?!J1Geh1whuI_GdbWG2g(dYiZ zv~1bZ@|XMj%*aW1bj0U^uTPo}ve~3wbC^CxG1V_rR=ibb9r7e&JZb(S)|?9vk84Ft ziy54naPvTOO}E{+o`O`E=K<$5b^`Jfg!xZ0C?sh9wb}I3 zBJtvDksg8VbIZv$OI$7;cV4tJrEKu>(MK~6H>$D3{{xJl5ow>*)L$bCXjZ)UW!d_ z2<%hKB0y*pVv1codT0l` zNc4l?8eO>ixEC9X1Nt}-@t^Jk7iada6I=V!HcEY5xYyWQ=SiH%iTHd;Q((}#LN@te zU$G#q?G#Q}Rg{m8iJ2Ak1fTpi3`;D2GGX{DfU0g83B&oNS7;oYwRU z5bSW?j}|F z46=DBI7)>&6_~U6l^;Hz3+X(A-py%kY9rqF)mGH+hh!c*T1Y-5@%)?*)-3Q5!wCX9 zK)Jn}uh)W`1DgSAlDqclS`mQn;KXH!zbbbvtVbi9b#sA^csbL89d2;qSv4lL+u4Q` zkWt*OhA7?KF$v*G#^}|@=MJCN-ZbmLQV+%1Y){xHlMjrjtZVK)@?h_$=C;iB95ZNs zX7QA%l||3wWOG-u4V84u3n^L6O-YfkW)N5Zf2xK=p@&tM!e0lv zDx!L^9*bAn>bK<=AAGB{Fwz*PFY^vK9~N_Jm9H~kT5sKSW=_jA>2)kyY1Y&khtj{& zuZ9`5bXJkKJM+OiMtcLStk2RF2T!kGn_0}|Kp6PH>NTtQeq*(g>M)$8!UpX_7RW+b z5Q%y|GFLtQ1|NE7!pMo!^dIobEQFCL5(b2k^=iWCQ$QHXOFEh5??EWo>NDo&mW_zS zjnB__{3R6GjsNDc0R zj}E>M(~D$ZptKoqLR_H27SDD0P=`D@2e~kmxrK0hvnpV&Kd2+$m$Qe7g8LdFdf~`f=SP*)oEuyJZiLq- z!^%B( zklSSB6|B|yQG6KeDV9TH(fB~CP-j_LSE_T0mH6=D6{mMh-(X3wI=OsN&FIN5jL6AX zrB}T;riFZZcJl-IeOIfptF~`E@zQ;(Q_`E|<4f4?kA+Z!DxE`!= zUSDXWzpyLXfi7T+HzyPZ6BlEln}>&Xkc)=wlP|f3z$H)ZKvzlQyiSe;dy*#lw5O9d zv%`tE&Rh7vTPL6Kj$ZTwlHn-_iosYn!v}9v-b9x76vtxbVJtH1!(}1tV~Cntta8*= zWw(?k=<}AdLn($yD&7Aq50WezdXObTJxkB-sGd`hS-MB+NGdB&Oeib4d4CL#knAZ; z6#m6CqB{CbN$43jwCed#@il|n3ikEAy~f2Y*-$laM#KqcKfUY71j9&( zw2ABKt(dq}mU^O{xYk?nA&X1(J$bM+Es{Pp^GceB5YX0Bx88B1}i{~ zq6K8C(s;Y7r&s5Ywbqu029?y?W|7@I)MW|1oJDr)vVGY+te#mcYaN&YlQ#gPA4!Xh{Wt-Gz^7gXjDs6$|M9hW!g;3B!0dWNQ&n{UTcLrGDETI5b z(gd|9V9US`iINov%K@sL8%Z6k)ev%exv)3VOIFrbF@>3IS7&k~l3{1mLdYm^_hYI% z`53yP&^bL^hj-5Brt7r3fc7$!u6NU*Wp=*9>_GSERNbN7)t#=rCMm-%O`RpvTQVp* zma1pjWj;k<$Vkev>Pxy@06C>XV>fRJ?HBEPFmJ>!$aAQ{Q_^C?gxz6+X<*Fo>Th^^ z5#TR^PBozRbb5{NSJ!7j0)aB&x?UH=*z5H@#F{`M; zZmKBDp|)TM_@h`ZGq)Z2>5o4vUDKdYQ0}P4q03|~k_&drHUfdwjo()@1pK~(Dq_-N z+&%q`ehH;EUFo*mlLMF)^b@abbyeZ|#PIMG?{K@ub-!iZvl|#~R618<0{>%n7rDK7 zw&JW*kwaEFsa_6Q=^=>GiEmkB>c&Mp=A>n^&&hsC+OTEHkOq~T*4}OW;~CZ5nEUqD z74n1mg=;e>p-u_>3E1rsaH7b(3FKnWt6*6LcUCc$kK1m`g#U!p?Il?<-XI~jVBEd8Sb+O((ld}>s>T82t-AW>Y?@r~EwzWNj z)2l1P3_?L#*@rT*C}(bOA;Ba=^9%UFB9Ie6zQ~>~YmE|?cwt;uk#-~_D=IQ8D>5pp zpm=meX4!y-$e@5p*?!qXr+FkiH7zVGHMyg#xuhx}te{Vy7=zPGLVlV~6p9gdDOxBI z8YR?GnGXjh4M#tyUxrYg90JiC7L$-4W?~7TdZDql*0V7oyh@CZt4v+i^Hp~rFUR6S z$IM?!<|ReOOB1TAdippumN)+pFBEIw-I&OtQh|_S&v|qGF&qldO@rsY&7P}M!0y=0 zAPWpjbW(YKRVbMHXj3EWK&E`-uO)MnBjftjdJIg6U{6n3*7I-=Z*Rw2iQElUXskIKOmi zH-t84v!T zrlJiqW-#4@cRNDazG|i>=*1WIVXl1y*>TY9(^URimspHr1cDw zDqeC6+B4ZnJ8QDDAUNik>eH*}*ID896Wp8%Mnz>wt-%3BGs}C$`6so_Nc1T3bPghG zjJ^WFMT8Fr24rVt1qYVUQI$PCUk{f=4?n)9LYlNvdWXeDZH_pAJzzU78H6c23}ycf zyj1Jq$abW(a#ZMB?!5xs9@_2RtCz=F&kV=tSut<42-_FC^z^Q8PbY_3bvxJSS{8<< z^@ZSBf0|%4l0|eyXe9X~R$#6h5~vaBCXyc%=gB_@XuP2(;{Z?RETLGd!?ot`zYoxg zF|J5e7gfHc*n%ol;}PKNqpHdh`%I3eKh&tkO7x3z^Z(g9&oQ>WSpWEt zmv=k&UF(`wD=i=c&5!L5jWAV|Cwe<)2R8J~6hwu}o*qDCA795*nJD5=B)O9%+6o8A zoB^IhodQ)Ze6eJSj{e)()w{N@SC6!Mt-FgWjrMePyZ&7~;%mV7gstp*Q0!{=O>p3= zZzOEh(f>HR$v2`ucYE6`^&?=tilkwrMH>md?PShmr1@&0HjT8j_s>in*mv45C zE-xH7sU%OE5IEjcV*fqhY0n+TFKcQhmFDvAl*1kDzXwk-_*(oc zq~-PJru7||n%TcybD_M%G(Ipvn^!VvU|~7?-T;T&nvWru*a184Wu)Ts5c=fyl)ALa z%C!2)8t?ik6_sgemF1J|#&Z$t8;X-kyInVBay@=S8Zf24esVc}1IG6hN`)<2Z^Y;Y zsjTx1W7RY0ro=-6_9=g9uon?@Y*}ZdG3h)YjnS9Mnl9kQRQG3j(Cl7#Ut9p(@bEac z48RhQp0{N{|D3EL@rg@TrzG?WU%qPC@GB1vt!~mx?cLkt5#gKt&YL-UEuBkhJq9<; zTl;oIBF@+0O=+gI-2q_YBS;4Ebt2NtTj!+ojy7@6o8)o|`FIeWOvkf5q8jT>{Gg ztoUfh2q|6IND~{$HuAtwibn?Aca!8V9b@+ma{>UjG|9h-j;E6ck&jb0iF-QQBn)$_ z$FWiHe1967LK6q!&7@-rEo`i`Soj?JvS3hJ7omwF!smhXFZ3^gq(<5obNKN8;_W-& zn!MJyIq%3~WRZjwAPFJtkpN-ujUrn_5D^r&briQEZf&irj=HPWE^Xb`F5B8=$GvuV zyL&rt$L+q?+g5V;o^#$L1hwPd@B4kFNZyh6J>wbwXPoCmBaP6`!TY3)oi{V@;FI{I z9wnh9ek=YOY2aSrd9%EZ@J~RL#|u`5*^YE~bF>TC^M<26< zd%aiq-gvZD_#U)bjn?9~jg$B%@DT)F4$>#ieVue1tu^6yK7@0l$Ti&Rb!6aPk9Xo$ z_dD@d%)2H69w2gVgc^|!t-a)R?KEci*1L%|A;Ug3=gpUUA zx8IzPx(3;Z(!mL|2Vv4evjL20o5qIr;DZah7oO<;>@yhFq4yw@#*_+M{GmN?2Wmsx zKl`kE$UWZh1>qj&v*12*t9kb9?pb6>9(f)rVjf0s4IOV(bSJ&WZD6+Y`@EEJK%E|7 z^V(d|O=hdEx?$$bhH71suCj3C$ihk;zi;-iy1HSrYvQA#;%l7G=Z+#Dem-C}A{*R@ z4f$lp#AK6SUM>6u$1TzK`A{o-8_>5mS&ioT4O;z~N+D|++SXN8GGRhVSyy&JLR?W{ zd_n=QE*n3gv}Al|8SHN!7hgo>EUt&j+}U0#(taT-0J#~^6IvYtZER^S8r>GN)YKT5 zIVmm{A8lzY8q*oyIXa@Yd`=J<8}2;w1-}w(GH3sZ*b&wV62ZfKQ5Kk&lYDn_O{1wS z06rarPyFb5ZF*;CRD(97tCRMpi|L_!Lg5*g<1V&9oj;3R2eti}e~tb1*Rj{G(SO-Y*C#lJwnia6OZ0yf$qEA3 z4q4qyd|lN0cwLz$l94KSegIzy)52D@rJr4&o!&G&EobwW+F*4~XQBA`=u>w|hE0n~ zsm7N&x(jR#+`>`#!w=i5<717MlEzoj5~D;UK$0LC{_x+va$BKD-2Yv{p*u_C0Em*l zfZc@lf!zd%O0ZLgpl-(m*&sU?CyDt4)ax2X3WfZRZ--{H!RtWLl+~2a?ygKz2ZaWRnA8LJ@9Xf(k1B5} zo7$8g?H>}Zldzn2%YEhHjeQwqEIT3Hnwc4XB}^lIX5Oe!HKzzo8Qz{89T^#ZpCMEi zFnwHVh>xEx5mph<_7$?7fWt|=g^(P<2NtUDsNGEvuiXM$l2dd@;06>UhC7^xVv!ty zSM$;k;|uC6i;m}LV69*Qqx0R+9jFRt3dljRcV6vxF(h0H?R4q=1UL|MJZUXy z57o=UAEC)wVz~UKnpXNI`-L3}3f(u!SM(bi`&+Y2La=s$NaL-0->tl9JMuwrM8F=y zpc4%=kCchnjnAP^`A`xc1YU4n2M!djLs}`lqkK1eWj7*jh2Oh}xnnnT#~<8-$fG>( zfwn|L?N9P1D3n&ddp8g0$oU=%dkbl6G*W`kpRwS;F_08@OaHf?*NL<+0JIVAm^%h; z0UbM+y#>z|o`Wly*#mbHY{9c8)~2&FvmZbAM4023Dfl$1dgBc$d#XWyzv|R^B)`_J z#fc{8t9x;8uk*fL{97P*XvQ`v&rP`72wdTWrGS`kJjv|(ON}H>FN>6!5+-IxN8%kr zkNK>9)#fB|L~62cvZ*aOF=yx@bc2isu0f9h7J&Zppp{c~HamLktl!zkxW~SD;f0M? zt_-~gSxn#(vFXrba0A?iYpz_`_`(Z=&)PBYGS%?#D7#IpK|A2;#w)mnKGOLt=RNQ~ zd#VMVwS&B8;|sr#m!2i#0hr>#z>9(o;ytw15FK=3dR^Ug@>^P(Vk;xRSK+vp{HBza z+u&E2&l6}Z<4yFd*^OCF5RgPL$qA;1@e$_743kJElIbzL_vp{YcOE_AR1DYMcY_XL ze1_-{yo32-pp)n<*t?v};2-O(=RH*xX&2gu!ucsT>R{GmEKqnsLVRICLSjBD6h0Ji z{Rss`7w7kXLO&E1IOm1)LVNgO6te;zQ37JQ+Kt+{&psol4`{&ix`1f9uflaN7oGul zxCdwicm{aFiHf?f643Y={l4dQf}03xy4sCfyWujO^HSD2u$$5a`95GP*6Q$EgnnIw zOHtDYA9&p3dWV7D!Sv7@==B zV2?0zuNVnFDyV#E#?OZ&gobOmr6%O13lELg!@W6h?^)-)V3t})GO!k(4S@>qKWoE7 z6ZkFRx&bc}D%8i5zVvVBmJW;(@IOoO{}DZY3_qqv9RU9?ToB+t+;@mOKQN46Na%pQ z2_2j&56I63=mND2%60JRAbbMoqRHs&3~kg9=mO7plY4g{81{|?+J%%3!)K23Oeyzn z9cjn4@A=_CVHArKsdDXmPQedvqVwJVDz{<42)GgKV&UBcH-HV(@Ph)uV~X646P`59ST zi|yw^n~ahepV*T0@Q_dw^o4N@=ceO>{KXsj$WxBsgEwN?pzEH5IU*Q01{h(6AY_qsljcLHt23>ZZ+7*p77#M3^|xh)id z(grE!;`KCl$Vow41arkjdqe2f1o+Ab%TlPTNvHiFNubvx=d-vCV) zduI;hGzGO8)kMqM5Re4xz(zU-&K!_$eq0Uq=l75q?j&RxEV{&r+J-omE`TCS6I zr(Lqnam_>4dE7flxA?SM*8Siq>R?PO9sT&oK&hb5K`(%0$49!aUhQ`D&+eKnjQfy# z=qfL`=V~`-hZ(a`CAkSXu5qniUZM`7KLAmIwCce#86KQ>cl6M42xqQ(t>6NQ#i^zS zPoi_b3;_TUiM*mXzt)}^TAgl=O;*Ze<_xY)2L7dvsq>{@$ETwIzGb9 z17nGg01dJEakJn&E4Mm6x}}CX&#ZtDNc-wx4EGGA3i?T~`(Xjl8R(no56lvL$G^$I|66UvL*b4j3Os0(Map%zBV-b|N~RMjJjpZg+8dZfVSv z3E}?5#iNb-h_SgpJYb0}D9JKqriGa@GwaigTJ=lSl6((8~wA*VsV@UBKs7NijQBgAU>Xechr9Zrw`-|@Py99g4020p$#&B zQt3a>BqWb)NlhI+GC5)Rj7) z!=IB!K>vJD{J^KoB3Kgu^Gn7if|&l~1I^mvz&}P+XGlrq)Gqwa$n{Yov5zWr)0FWj zvZ*aGSgTNlFvZjBMt-qeuaC``cHfuTrs{0^>}%hn2jCSBBAX!V!6}=}{n-`^d(n*E z5JVGTPzl`kg>WAfGj!hfh56U177M@CeIs(j419r~V@WL)Kn$+X4~bmk=NNois*h$+ z75vL?7xVo+fze`~T}L2b|7Kh|Foqu|(6HzC?q(b-$=8^L@GqYs=6|u0uZdoTuR+5- zbpT-4!FUU9CgGFPl-lV;B!DbPDTROw9nV#`9{8o4z6+L%k~Ba1N3+cl0^Cw=vEcd_ z1crh8nf}v`mj|*2B4L)mv&xDM7Ny;wgM}EHXJw8JG8r>V)`AlpS7b6&DwAD3e3A`L0w0`q2qvCzTqQ^S=bQu3-p4YnG^@Ze275fO7Y;mL*dsi{%1 zg}a)Yp>K(RJD%ddrSjLquZW*&xb;@o|J=i_PjCvpvlYJ6Dr%*&4g?KR9nO%K9k))L z@ErUvVnnH`m1&!NTR6LJRq|GtdZ0z{(RuOT3A9Kk)kUq;+SubHM&zh~=Wpgu3m6sI z@MaooXeDt0is=sv*GQZKAI9&PCiACVaf<#&xE%v_@bOYxMX;91XlQ|cUlg4weLJ#T z6D~Sa{AOIahF|vO(uMFpo#X5A7ZIR?;W)g6V6R;hE9&Bts=D|GGJ=&#wXrQIo=?l^ z9G(dY7cd3=&jO~86)p9W00IlAv<5O<8g6xM(;D1 zvogs2VEgR{+pmd80TyBm8ukQn(0EW;EBn`w1Hi_8HfgtFw#}h7G z(GR@)os)kV$7sMkTL&V9`E}b5Tf4ho>+W{Eg@y_C1I#bncNp#?wmFS>;KRf};CM^$ z5A>hox(3qukBQypv^T-u?WSw86B^9s3rwtSOiEE!OV)4;ozt|UjF!yuxGH~sS7&}@ z_+;zk_=R5@CR!&(FM_!_$Mz4Ti)w(*^@3Mya7qMA!}WafY)`urS0)*aN#yri@XZW-d%L5refCf{j_gG-V}Dj zyG6y9Z+Ryf{=d2J*ov64gXylf{EoVO3EVGkwf&w8aw12x<2C&Jz%4h($LFh;Epz>k z!(E@?6tsUB@aCa`F%xGMf5plpdqz8YJH3W+C&G?f45mH84lmJB<`lqf{1|hXkt2gY;0M`ND|H3`DRT zwj(E5Pb8dyPsRF4C+K2TA*^nK)HhDIWQi`$mz+`R$r-;`?UE&0T$3niTFFKQDOWa0 z5`!fPiP9iAvx0|*llb4HN<;j_oUE*ziR8Q7J!~)NPl9{?=)3&WL%(}FAIZ+<=TV&snwOpZ zOOWVuJ`&I$>c1W8yUYgLk@$q%*YG@gt(QAU-$`PajKPTt!IK6RgPhGS#P=U}OgXly zVnk?q@H=-OXEq*PUs0#$zr&}#wAq*LJ@${J)IP%3L)tF}Sws=01$x5vy89f89zbuR zH@VlG-Hu0)??c)M<2D=Q8tFTYp+Z9=EiiiQ?DMnJGKT;1ACYu;M%wK2_|B0Na;-^q zN!Hv6BMEIV4pMRS9sVDXe`ken6RIYZ;gp5MCFq&cqSHb~APpMYAXkqT@W<~YN85F= z!?WYFCS*-*jteuSr`zMxn^GdRI>vhT!HPILcfy=zP4f>)sg4d1sm7>%3|5;hG%z`$ z^q$aknL$zN-JS_$5gA7+wB=D~OR$%bw1sdAa0ielNyLn$btSBM1j{;y2S2Jz?P~3v z+tOf7H1(r^h}_x;MkEgyDQVIN#fZ5}@}TPZbv5&CNy7|`&B|HAHOD*pXltg8u zIY-{T0Pt`R z%qc8UVO_6*S-kPx^rVoA>(L_Dgwr%!Xq6@ek%q17QYpIw#Iew>AfJdXwSpXE+Ki#l z$}SZgNn*l8=DkTZUHarkXG;U08c~tB%iq<~r$$7Y5_f7{hwqc2vwCM`78I=GHKM(w z_0WFs_m2jD|0nJYe#jRlgXWPfY=em+%_NLOnyJMHQ&QO)GZPe+q#v%B<>Twig@^Hx zyQA_#Q~86*Nm8l*yp{gQ#xhnE1n;$ar`w4ja5Mu=?hwr+{t|&E$?8zZZV}dEf;h0@ z9Xfs5s+xIB((2VVJD0=(`ixohw^(lX4%^$q*TFM5c*Z~Zcjzh+$o3#iM8=)u6+l)h zDcl3p>`L>%|18ojl4<Sfnn6V{H=g<-8Rv z3!fpZ*YAKa`3c?uR)s5j!+BYe7 zm5wmEuwQX5?8lZ02h=Kdt#JZd#+l{~V?mY~lH6-yJu{(E$lHgt&9G4>mzx$Dvl6eB zs7{u};k(RbQngApUj>_Du1F}2LF3{}rDo|uwFJ#w6=P0Ar`E(-9Y5(65h#c3Tpi&T z#zlqs8Oh#iOoT#@P04XdhdU@OlDgIWW>`-GoD zC8`sOaSdg-vaDg8;)F^9I~)HxCdHT$$$ifxUl?(w>M4nD?6tp!DlI}EEXq(W2{tl* zYBFwN{h;lTMZ_h;8g}qE(l$WNJ(H5W3AS(t6=nb@GM5}Lii)rJZ0lzg@lm4qO=B42 zm`zO2Fl$Et>uh|6b(pFB;K6oyRxR^7I>moAG!K{tOVKF_{)B^+;YXF(rZj%1Qtg;1 zGw@>O!Q4b)EJ|?|x(|(WewWZWh*MhM2;C=qOM>+91XRF_9SymOMx~nBArrn^43UEn zpbJQ6GhA2Y0AQ&g5dV-u(2YbxWT_~mECz3nD3kiDWOG##hY|S=6LK4=y=pt@AR{A4HzKD_xhXs}z;hm(W#>d?rj;+e1? z)4kc*jj>!(aANK9sh!WQUWQ(QO_^Rw(P{H*&H2W$$cob1jp?G!^xDSEq#c_RKjZF;9D-AFbV?E{o7ES6fI+etSebokDEa zAB_&);%@oxkJCkGtI2rnht&bI*nGfk6n6?dLo}8Uy&u7kULn_eST?sx_vKaQCYM*@)`dk0u{4e%I2 zJItOE;kURWZ zemT?~kAQcJ#XopOfp-{rZGnwIrhzXTxXF`>(X{;d_)KEBTI|iPaX$1~+>O@;-V}AvYgQseZg}Ri0Tis@n^5X4IbklBI6(&)4j$;1dS8g0r|BU^c=zFM9GfSfPPlnhw@}Pg~{xT-u8YQ z-+}Lt%jIG;o$U+Fiir62`LGR~_S#pjK8m3aBEkXAKAPzUcRhnMtuSd+;Zh-*N4R{NWq0gYTIgX{kGLC5}CqZr_bEii=T5 zF^q=LMrJQ6v%MWMa zU-4Vg)R>I3QFUG0-db*JOw6?m|A;UK zUMsXq^aLGCFmQ&9C7=^BmN1v(x}R4NU2o^aN(Peqp*DC9otibUB>Nr2GC_QH?o=|v ziF}kT4z|rCN|bZuN0J>AVdQosUr=1TN1g;%ef`^6woRjuaNgFiTyKS8ElTNsrK=0o zb#^+w#%EDQy0OH^U#r|f+vc2C5%D_+v<-XE=M(Jg#2!RN(uKjE&_g&0qLG*t2BG>7 z!KDB(0A%nh%S?E!zN|Vs(Be2D@~!q63n$iv(i0-zVQ4a6AoKV4p05yze24qC!?=1Y zQ@C5Ntq+oiiv=`6PDH|?C^r{b{DQB&6R04Uoa4#8Ove}Ws*@jogk$i+KphscSWAi^ zwSaCPU@{PoAKB`d4BwAw*N#P~&=stW=0>C?hE5*yZ=8Yd^i|?;M)|LCvjWg-7^+9> zm7L6%`feKIAaeG2`*Ku5FJ7tZIu+l2!MB-I@W*)n&TSlB$`< zrZ$8zp^Z}?oLN=M#Th~a0+K_6U)c1b<2$`PK}^L*v|k9LdU5mffgy=Ofd<2zma+R5 zJ@fS9ePde$`r{M$5?CLY>jhpIf{Ew`0WOG6BT=s0X&5$Q^pl0UFov|WKCyyfn#BsU zutfmj`h@d4|0Y&_S~UXitf}%zldsYGy|(@I=^dBF%Fn85Q1^%`AG>_D*6(jS&tJrM z9cu4%{EY8m4xGQW!@t9#jN?hG8M7{>PSe?Q_DoNww$rSPW+-?x>r!hq9X*erdb30B z+ur#K^Bshp@Co;P+)sHv%S8)(8}tpZGwGK`LHAL1_e{VysVS+EsS#{sDhO|a!a%tb zx`iJBhkABZql{3)3=u)gw*^kcMH2syDob!*Nu^I{ko-1(Z-l3ZN`0d=8og=c zT$@HL@|J5`GnPI#X?HZcAkZ}kG0K4cRe5OltfcWlawne}K^_wu7ibIMf>y}yLs|C!f&@R#CZZYkI$VZ@3w3vf^*;B->D%e9v^_@VqQHuu&et~{1BZfU%= zc74#=Ll;){A^(fQeu_{qsG70k{jja#VA-xm8!~c_JhWxQ)6XKK9kx^K|EDF~{D8Dw zaea|4#w!K4vwi%N5NAviC>q-1uk#0yW&)|Ka27%2SR#s@ZH1<$rNWjru!)^O?rh)E z1>2UdKxRl#n6zhH_fshN{@CQo^t3Qz%*eFi&9A?lSvh@4Q3iV8h2DiTwRT(3`^%56 z>RMS4WxAtH>9=< zNZ?2dY=QzdHzZrBwQ7~XKPKpLDjq^*w-i6UdoP`HsE#g z3~SIWbYSX<-Y)@KO}=#4*Lh5}UVA`YlTf zlD1C0b<>EdwRag;89RDAw~QIrT&A}s=B73HqDRq2SPHnUC)pfdZ7X2%tC}L4%2WMU zJ@@#lJ6B3plQE>c4YmiELx8ox8AddyMsP}zG4rVNP0IcF!_p-1AZWKn?Oj$s{7xwA z4cr%>T-OjEHU2GRMz~@18_d7Inb@(y@fa%uu6s~2d>(LPNmldU@iX#Jz1%SkdD)w#S5ixp%DD(+i$;h8hPV?pZQzy+mFD0I`VV0 z&(1vzi4RMVLZstF2SX(wGDWaA-dU(hzp|`^dgFw>@sLc|91p!Mc;y`R!sd9?pU35c zTni`u7DU!cJ0C_XY4`&L5?0ab5M(iP`9I*@YgfhVx?q{{qFvQpIhGK6aQyp>1j!TY zN1&@cxR?2;8456h-!A}Ft{xYek@=LrH|{M0&ljmd`UU#|tosgv1CT-92v*_(ce-Rj zFwJtcu^(*T(J~c(v<=PICZsK`@rl^6W7Ib(%SQN`5Q{%UC1{PKirrd&_^|_W6pSD3 z-~ZSFfu}$oa%zw_V6`|UbR><$xFjO@j|6NAABglLqMB2KV5SsMp93;*%RV5Dt%6`C zlDH(h`J=$-Kq~Wi$E0s2b*y009IPOcU442TXprDbA(sn$*3c*7`_>92g+TujZg?Gn zHd=L{{HvtMz|r-$gxX{N`h2vZJHp0xx83D{1XreaxyCOUjhr;c@eG<)Wi_oajU(<~ zp!0He2Yy7Dj33MroKldQ7xb5|!GjwFmIOv1@lN7OqV60HPLQvX zM(t=AwK_4*9v>JyDY&X}SgLuO`NF(){c}2YKQwXKrNwcpCrq5NAosb75WQ(^VbzF9 z175AQ%i@m3O4z90Icqr0*RgFL8*ukVvUd+hzt zsZCud;!bn>luOQjP0dYfZMsG1*GyejTF8~&qwARAmzQjC_OE5cOnmS3sxpDzQ}Hmi z5#CF+KOI0}*n~Hb`4wi|gIHX&;%Zc5g30YK%q;HmukoL}w54s;`Z%qAvc9Ngp{i5~ zo<*qt2A)M0nG#$s!)a5Nh!#&-J#Ku1Ha>Df(QPvDD!#AVeA!jZb|Nr z%Z*6J8YwJ;bIbYS&v(sT^2{UiXZ0+8jETdaZr`>zKfR!S@As^I)d$aQ*uG))V^7|` z&G9v|Eg4nacXBOI_Sz_88zyK*mJE6Ojx8h0v*8P_Wb#A&^}qPNR(?mKL{o<;Kq%KHaox(k*A% zc{y<+$?*2$n#e^v1`dk~sutHC8&!@zdHjyuO1uEAlx~x@z-DPTfY4%$4c3vE;`0G+{~^3`T`#b5AvFYdgOw|;F8#Co!UmMJqjgl?20@0 zl%(Qsx1dG-G0GTQakY;L&P3xact?Ou8Dk|UHsLQ({=XfcFyD4OU1`nPCr4WR)Z^%? zBV*1#;CL^YTQUYjHY5on05KXR*+}}v2_WJDR-_UGI)x!p7Uto2=Ysd^@i@&GSkxHo$87x9(?8&aXeH`H`^apFsg5VJao~Ju7rUgtZ*$+iQpA^x?a2~!7S|7L zAs9oT1aO+9_U>oqkA4qx3wrQ@kb&UE8@@IR!g6J^Qxp4c)81S}UTfB{aFCZi^6sWeiyL?L1( zM~p6+aXuA1>T~e>*tq=UOPhDNOVt}ETszf^j^Tgdogqr2;Dd{j>$#Xa4~$EGfyJ}zbNhUbIwYj!NiPbsY5{uMfYe%0DX?)du0 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

@$%UOnCy3 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 z zw@kY;8gkhAxtWD~t43rOEOj_iW1~t$O5J5a^TZ3Q*P}W3mpRr%-z-#@Ds}4Xpxk6|6ciBRHxA z(Qv^YbM{WJZ!9Q?sl4Yro!Eb|<6NARUR4WgA4N~zTAEC+CNB%0Ah9hxyYCbFukh@+ zU`zybgAD;>g-k1i2!wNqNvka~4y5Er--ST_i+lZ7u_7T!=6_wGp`_LeVV0uw_&6$E z6(OWWj`QK6rV;ytD~0s>2&u{tBlEwh(3pi8Ybz|8L}*&)RY^k)0`EGy+TRpd2OJC+ z*9ikMxQS4K1BeH-lTu->0R$;Xg)R%Ay-Arc$?^v4x#+(ZS;8(@rIbeDe?75WJi-(j ze%>LXg%K($JuW`o|3na|QI?9e8A7v0LAi|u(g;&Ez0NBzgi2NZ*Nw)+`-1=tqX9?) zK?iK40URg?U$C_?1qEa4dpn(U&-r^Q>jtjQ?Wm-mG&K~|_O5c$)1Somaj#b<)6;>wO6W0PZJQ&M7M zlRqyns#`k0Mi-tX(ACxH1XR^Gm+owwB(MKu>zT>d%=Q5 z;d0^FmX74K>cFQk&kcAvwE*fXh>ifnfd~Tees1$rYP1v)rv(U`x6w0q* z>hULnQ_w?#NFxUyZy7nU^AI&deh4oP-+hBWS=(B_ToPXHZTFOjLOtRPQ}aY?On6~e z>zYojDZe0Atuc=%j8(Gwx`mTQrP&{@Ob@5R*obmn1jE`aW9pVyl$%`c*wGbcx6j1k z)gR5k!2#^Y+|E`9Pb)Y(Q8t%VnA6|4y0cYUsGa1rGa zY9tEDbYM~hIuV5Cd!3q2FYneQ>j{`8>l%uot-&n#4-j3M}9Zc zf-k|?v2a1Wei(u1BezFQUJ79?16qMX4=)!S?1?YA!(_^wGO>|LcSNjI*e#I)RSN26 zOLF8I7JpBpRGLmj6k?EqL9p#1gzDWxf790t&rc#NX{6j2qF}PRLGbI%fzFWx=R^}g zi+cxIIVZ}{XMpM1$hclk8p+)ts1ME43N(5v##ViJq@(0*sXuLSijdHlKnWn=BH9iSFp6 zqbWc^?^dR^Z!-Hu$U=aYa0Y>q^kr2GKt~5~;`XIM&t1?G1WZmr0H+WI4nJHUB2IMz z3u-~NzXLKp+JsPheK;$p!o#K9ozn1dDh74h<#LTBCs`-eNi^1K zDJ7P{H}%YZV`4iarHx6eVeTB65VbnVNK2XaM58|47?W*PX=`N(X||D}c6Kt0kejC6 z00uKzP-rk1(-LG(S(MB$T9!!?zi7|10LoNOR=s23d z2SamoB}2mv0o#hBr>H$rR&GOTDzK}0zyI~H66e*#Y|y}jE3kTNJhQ4KsJ8{*@5+3 za&iiA5%j7AKH~(Edqbm!MpB%m26O_d)$zb@gCxo2!9UxjJrcV}5>A2TZ(k!^t_hbb z!dDeF3I&ZtYASV2WcbR}VVZSP6>u?Ja}cp#;hPE-3VB=Q0?}0=IHKF7>VspN6)qq? z{yVS3gn*}S*iX5PO%NuZ3q(|{Quh;^N1cj52KNLAZYJU>bb(GKOgsE-fET`xzp+b~ zi0l?4eGFt$x>#%vmxfbDTFfeA?UF?i2_i`tkp7sMRm3Jp7fJ16F%d*m$m5h=x)jJv zXioH^ihu0}=x5FxcujOCpf`l_M}lqofc+Y5EGhLNoXa~Vw_BnQ*0i;(S>4vQx>I8Y zyQ9*Wf_7(NUH$T*W(N6r9DU6B#X%hLxhr$OI1sW~fNUl;ue1UL0|bbA!t4(HF(8Xw zv?AP|s8@%=nrC=KI2FaHP=HoYi~Kj1Oq4|`#^pkY!rwy%pYqf6bNKJX2)I$Pq>8^+A(JE{{+22iK;RC{_ITHLZDxdWoem#x%yjCMd#^k9Z54^0KEH zV$(|!MAr07OAH%X*KJtaJE*`}syyx^58NELWChjSIT9CY`rKhJg!Wa$rx;$f8xI_}kycQ~+ zyr{N*na1FO4(U>f$TY9ZEQT^JSb!$u$$>w=2-;YZF960Ovkw?pV&;imfbOb36aFGK z)Lbv7+nm}RI;SIzVi;kKDKs?#on}i)4G4b=)|}HI42?9%ShABFqt_2({EPjB)5ipU zSWJz#akB`BB-kcsh!*HBNoL2z8_=5(%n~T)2yobZ_+MU+w#6(Pksod-k4kivr|5DT zW1=#06C~5jC2o-+*AbhQ9ji{VEmn;N_J;Nap~|vCQK*DUrD#vGws5i~JdFXn5z3bP z#Gzu!!!T(`DRCvP*Ao6ly&r-PUG;qh>m;6pCbkfq0=WYc6M>7Jx;$- zrnk{{c7YgP%Qxz6jGb8$nqbv~T5E+WJ{5~Nyt4S~!581NNZ@%HByl)l1tdgrmXbz>~T%mK3{g-2#2$AM4{8; zNuJRd6*VRjTK@p;r!e(>TR?w7o{tV>>XoY00gdAJ5i>{N5vlGT0zC-qDxdQed$M<0Pcl8K2z zVmX(F2J@yt$e1A1rxc6Kb7xyP6{r?#8;Ek0627JUHn4B6f-ba>E>571+;A8I>=Pw= zHy;kHBddHKwb=toK&#YvvXCbQN<&HN0KfWtJVjHo!clWe#tQ^uCjLdZrm0y%C9M=) zNXts_d6?EjN?@DZ5?|LP3qy&CBox8_kT=vZTvZ&gKe|2I&+n7dn8p2PYGpCD0>Y4LMvg&Bv9g5B5Qb%LIOj+ME(X#YeBkYMeg7Qf-vKlLr z9p?Dl+Wbk4Cac0KR%X>V)+gEoX?R*vq(q;Vli+d#9N&XpV+4laAw34@ft~<_P!S|31|bZD#l0CRIrv8s6|)hka$Q)m=wPn3xX7AwNR%S+ zhzt@2P0vg#oLo0WJZ4aktU;mSmJVOSB*nyuib)B+j#Ti<=ICO5T(C^_o`cvh8+3p# zq?Eu0OdD^r3<(T5_grQB6(7^ARg)tCZqF!OUO2X9zF-U&@CBSpWMq&?pdj8Q=S`wm z__R^nRWWv9N3K%sj?#js;WlW%=~+Cx;JTpp zcZ7p=AucmaO1v2CqK1m0?yZE=2!e8q&}@N<0zvj<4;Ew(y)@|V1bt`lG-fu-Xu+?_ zckdq|K9RBCLCnPE8;B{oeWHN4|bRd28j|q`h zyEaTB$TQOk4z)*>Xs2RE*sAC#w_E;{NUae)7b;<5ZY8^o(2k*%g4_q9Lq*dqB@%cI zjxbG03N16iihw7Q8ii7oO8k=avFbWad;-ah{KB;1U)T>rvWO-p2kY=<0ze2zzYxUp zz=H=u!e_V)#MA`+;G~mxHCk|tXyAKN#16jlFOf!%BrH^sD;GrTG!X^zB;es(MQE7B zV~mUyvZ8g7E_E^bbW~z!+Io>V_Ho5{U0Ir#nXgK)+fySpu#^+bfD=ON4H2n!dx9!l zLV0FsW4uZ*3h}}$RhP~vLB@!1L1l)7%wZMN);AaQ`IL|@A``!R4!~{$wD17V`=i=` z1H*@mMr8W!+1~xXOqO*#K@}v3mxyd(Bt)a6tRmV5>}UIbS$hw_sH*I7c`6IVhVfSvo@2}+c$YuPNGG0$!cG==GqXs5WCh;@H{J~jIwWd~^oxIw zl)i_yCiVz3i};rDUBdeW7>)^Dqxj=$0T#J{nM^BJ3mC*T>_-F<=p2dJr#Pg~`NM8t zADDF%>+r2)p_K^t*S%mTiQlu5`GEEvh~v|DIX?!0k+2D2k(ZP^*9R6!n@%nJo|U%s7z1R2Vub}n>jihn}>4{#r+QwAn9`-HcBJrDBMQ> zkiJMifGc}&l~e-jd};}at2IL;buz5kXTiu^D`|iiz)T*@7MR)++Y$N)!=2Lv3z6hk zXC>r=1GsLo!t}{1C%^Cnth>O(nb>EBy>lbY8SFT3IN2`|UM2 z5xuj>RlvOPFPvf+Ki+^-&}H(8F8_;MT}1A$dHZdd`z!F}R83NnX4x|ME1g$Sm%TVN zT2mbxh(FHxXU^|A_?;Oua%RlH@4)dtbMOc5y9E_>Y-2`74x~Uty%KzelU$3WI0Jw= z$#1ZPiq8P^lY3S49@R0hs7CI-v9a<#c{@HcZPaRlQ=ez#r2m|xa^r7rz$1r8O(P;i z@Q%CD50YM*hZ3wW;0?m!nHlzM;12Y|+%b2lwf0d3<@hJ{U1R2s*wa>Hn#IagnFY<~ zVrQ9Zh+zTmxP?oX1p}2-eZ5$OmO7DF3pJIeq?D6i=7Zi-li0@T!a4gMf4v<2^S3R@ z@>{OlOiNpo1h|LVyhxhfJ7VtYQPT=G-SP^4 zzNxEhBzu}$)Y~v>NatvjacS$Cf=M$LPiM~nV9@t#*C4h%8~SeKXBhA*_e4v>u{Nze znssWW8W9RORbfIxA^CMZ^7iVd(1$qYsnsAW!d3Py{%)b`*F&(_KJLsJG!8$02wUBk z2|hsfB)geI>^%Sh$R5Qqk(xu;KL`DiL;td6__MJn607M4`A#eDVY4_rzzVjuSkHkN z0NDJR7@Z7(Rpi;Bpabnk4S!M>4iw+;(!|74^84kyiR%tcUOE1UKs6T-0`oBLB^x*dYLUqV{A4*;$h>T#{4csnd_Gh;kVi806iws{-tPjg4CHIs1Z%{p z$^9^{w9FK)HAK#hbnJR00O&7|KN=tCA9#FWYM5RjOL;WK-|w;ajbPUIyP`H@nUwfN^E=_~8j#pGqBgha<~93E>;3NsgUILt=>fBJOvqFQ zBr{NxHB)CYBxve915rdR2^+F1TC6vG?^^t zqbiYqW#z7pj?Aj;@5_rJ5olsuWhmH?>LXnd(!i*c^C_*0(1q<8IU0HD*cA&SruJAf z1Guv2#?i424uK^?ZwLIm~G`W)3{U!-QUAPLuaYtquUmiC%*t zzvtVpa@nrl5Bog>mI!?&2Y>u+&*|JbES(=fTavrEXJ8)@EGgLC$#$}wP)Al+sjza- zxc>g@!NZ3S{>oTff4{V7<;q2u7|Y#TcK-LjJGb;q>v{3To@oRg?|Ud0K<|N>iAn=U z3)#BLJp-?B{hhJ!uOLV8TIRI(Ej?Ry0@y(3(fA(rP3bovog~@{EG}YClG<%VI>3J< zf!xMM>21uKx05Wdao>&USZ8J0ax8iNt)1Idtps{<0qBGG_92u2r{@N>%>aK{ z(qn=@mQF`vhyxV-JVp&!s4PTkJ8%Y(HE;om_=nBv>YCf|M@_ za0lT=Ski|%5)6H4b87m?89ZaWUuF z9hBF7MsabaDdzmMn>Ia5e!JI?9lM_VGFAMAXE*WZBq!V+G#SlgO5j~SZ$dML-l2Cq zJs|pbBm7y!bdx^V366N9mbV`Pl|-)4qLQR)TS!x7ls;%LXH82gnUPphm)o%a)>%e{ z>d^BlLre+qG-Jk1ruj`|a)wmS%2dP39be*&vLdjY1rc>m3}IsA>Y1^*0ii}?Xh3eM*%{G2 z!Z~G%bHupFY(EH-Xl*TGCY@e~zs600fl%(!wC?oCOA4vk)Y@t?OBFRSB{N1ZUOe>s zvdgsnZfJj(yL~!(q` z+Sa9!zHltKT=xCY#fwMJD2b^d5D_{<|JkF^K8)aYcl%)8gDuZfu$U$*@uGny`J=_h z)R2BtCgJwj*8=hYSBzx0WIqI4j1VF+ z$w)?7oF6lIpvf_HY7pJQuT_$@8!}~K)22*YHEYhS%eUOo(^);N#*z>?rDDv|d2^R` zt(-b-`|_z%cOkrb&isvQd!AdqYJShb+=9_f@e%3*)u^$R6Q_>uSoqnr1+A@3%Vyrv z($WgJQ#0YJADP(_5{&J!%T+(xf1KfPsP@{KDq?c;&zbr?XZq3p6+CAWJvZ~(PmBYd zBr<20JHW9)mwx1oqhs}I;eVZQ09PbnX&u8YXoZZ-!HKjGU0>~%86GP}v7G$TW3)oh zG=u$=zUI~nc*Y+%0302|W0*%|>5_>AdSa!3yPxvm4UUPwhFEjFodqnjK9%evpp zJklL?caJ(|;kxAJ3DJjoH2hK2;T~>R&2n0|{}QxzW+XO1$5h6l%wsESoZheo=OCuymH+J0nz*g?tUqTdynHj;6t~}kXX?NH3o=;~dY2>~C zNN4N)r>uDW&-)gqJeKwz$K9LuxA5K{nacsLY)uSvCa8Mkt?OsDp4Bo+N2+!9(qprh ztUGmP-dLgoOsIv~$Gitt9-aBXd zFHE#QF*KJAu(nt4c>)!H^CQer`eAi=GCj4t2N58b?xnSW0hMb z%$qlX@I3MT!8_PV@D5@d(Af;2I~)2-7btWCyx09UmG}MLBlkVFlQyx%-C*y@J}vve z-oI7mQolCPRG&9`VTbCPQiP3}HIKD#8s8|Bh1A`WWVKfZ$pb2LN_u}-J6ms!ktt+K zUG4N_t9?j7P||*$eiheVmFG(rg2oz3`Ah_a25fv_3EpAJ$Qgc)4b+9y0(P2e3U;ZG z$va^i_#sM*5?!mylINeg?aE);9cy2{?;1|&*b^1ADNB(wefb-kEwDr!;uxK5M^C(s zjOW%|*?O>77&zm%DLS931TDd*Jkb7vcgL(PCPaW;3w+7pD*1d|N(YX~N%-F;P zxp5Kx^n1KauL|*^M4T8xV?7sJ(W+O zzb&b4o(@bo;eVDjq55FclHgQJ`um$(chsF(yGEy5H({6DbvbKIp~CUjn8vEy^fetz z>z?iS{?`#xV-R<-PNNP_D|_n?QGq$Nw5e!%R_`|*Z?0`#f<94kcs|~DFiWjJR`_&M z*pif4iO-Ay!_3J$$xrQ(NsKaOKF1ZeROsAyfqIX>C$J_s--c_ zyJZ1>YSkw&5?A0iW#^?&!`wHKk9r29gUs2j!KO_0qg>FgJ-^E+MdauE@JuH`w=jjop5 zU={OJT}~Q1v=L1WRv5I}AP$E*dw`SVuHVV81Z-nefltVul73EY1+qS;qq9@u10CR3 z_SBV)(nSOPN{1f6dY}K2fC1kfM)x2)Ali@kfJAMOj>)eNRs>iE)i&v`fD>OF2=5m9D|~u!!Sf2my|~8` ziT`!`Y=iX;62;nw3gle4Mm~KZAuS8PVlMGQ!gIJ6Gvw+1oDB5&Kf)=%BZg57vzKdp zvBbkgt_=*g8%~Ns5k~`*JYNIEpn@dw>)_LaM*<&#!IygoJ_LBYxarR|w0ZbLTf1pn zVvZ5o^J=~8wI|{gp*gbXK9FwZ^`ED2q&+d-g*JV0?!_@V;`=DzT;OCeM?hZ%ICvxv z8WsW9Vz_u%gmwfRkWXK@$eAxDpm8s$2ZejmmH-36g%|e&)7#T)p}*&E&Qs#|3%K{< zTj*zB{F3XeTNesSh$8n7>jMF|1P+1T zHUVDp=?kNPBLV@zkNBKip>Wis2)$2Z`R8cJYwI_mJ_+fD3lfs*1j308Pn6SzlAIS~hW>~4Wx?sfqTDqVw^9|`UEjcm7Vtri$uIdKc=2+ym<9q}ytolY3?3D)*0s}cF_q`nJZBxvp{IT~Q!H=K|-Rj3J_5d5Pt#5)8flgvr2pr_xixY2q z-u6Y;d^HYFi<|0Sp%sBE#gKS0A!>zkCFw7@=F1@>s?gR&booPY2v{KPlOHcv#YP0nO=v+{6@L3;gY;VXy%81!Y4~I93OyG-1vtF?D3%NHu>e!weghmt zGX8+BAbl3MFK`Bd#mkFA-vt=RxtBV^8PyZs0T3V&4Kjm(N$9@-1NjugN8t40#;x-{lKt_c06;vhyhfohQQO4=1*AfEySyciMMCZE^i zKyr^@tPhrWRZfZT5!su{1%XHm1vw`_qLfZlth^gVl0qL`V1EK%obK%$vtAG>85xQw<~asz(u|s<899i zgBM@qs1K)5AO^2f27-i_YcYom1O?A60(W?^F!;6yq5|JG>DNGQim#Dlfd*c&1vm!D z3j_6>K*Zypyj_68i*GLt_}-H{{V^bz%Y&Cw0TX>cz49UMxfmYtbvH&RDcpL49#fp$ zM8}g}_r-_+O@GTz&=l8eU1-*gi9zU5f%^&lg?7d8c%|Zcy(iZRJl^}{NZ=3(k(W() zCcUYg3Rn?CBpj2^>(i$%W_+c^cNTMVJ`pfMK85y$V=rce-izB7u;S%c@!U={U4h)& zcoJuq7DLPn)HH(d7P9G&WWa*`l9?HCG<^xOk~DWZD+ww>bi0}To_Qni7gakFlQREO zkHYKsKGKiu5zQufD18B7n<{H&mA#z2+7XxbOxcCJ z@Z#!^Z|jF4 zCex%gF%@n!xn6)X*NZ;5D!eJKAVp3-^2M1L(Cgw31)MM%-$y192Jw%d0HD9%p9VxE zngZaVg#tG5ZaBqz2ucY~uf5AYD4j)X>d^fd4qz@4*h}L!VK0a+lGKqT@l+7&OY_S@ zL=}yPBoUE32S6Mf`=CBZ9h|!2yZd`)9^Tk||I7Pk;;$PN8mZPC9H6P(e(LT|w#{#S zXm(D~ZF8UdCL%Z}Jk(yZY3ah_+ux7XCKf(Db07XBuEA(V4_U){wtRB;(ih^53FaXq zCe1tk-i{#hv?6VT6KTG$HxFID0rb0+5iDo3w(rmb72a-Gf3od%XH{q&* z`O&DW8@Khgj!C13o>-jP)lkyaQCy*hKx|WZu)bjAf^8i$MrSnYSAAMjGI{;bY`fAB zrnGi;4jHj~K})4I*qGSTk`R@c(i#zwV8hnJ!u+ZYGls>7NX@Bx#%Cn8SM0V$N+j2= z0e-(?ozgOh4ukX!aGn8uc$|GiB4g+B_y;~&5BKXO5-ZK#oCzo;Y0KOd-hgu#t9KF4v!y$%;^vCh9VZA7k0L;`FVf ztfnGzttB{d!MUyb!XK?z9I1&Sml&lsZ*j%rQTXSF{~Qq*BPBF~4T^hYyU9rxT_mB(pOB?`e}=#(jq80Xqj4pubIv-JFJl#I5+Ly<0owh8 zp63BA7qK70`9B5Oku`$sqyuw8G%U!Cjb};NrfWBF8nv+fm*2?cX2D2^JI>@xMp@&` zwcmbMpeXq6+qE-~oI(va9yz+o@{Pe$rv@AI%es&Qt~8uF!c6Tw|H=RU_sRKQH0qTP zl?frP2G{nfo!vd%GquZ?YiGhi=Tv4cb2=nJ`QatV zj$ix(c|FVDeL;u~pi%s>z84tAGF=_a$d6Rln^XIF2Ce52Qe9|3l51`lm zQrTUbNlZQPh;%XFEr!ns0GPA#T%W0dl*=R_8_-Ci|9Sbic_pi_jc{bdTLylIe)cD#;zPsl5r!x_jrT7f!6iM|44%2(3PYrW~2tRmddyTi7kg zrZQGS>hrjYgqRrDJFaQ%&vmZoojbI&kg;)o z%(TZDldZZYBO>(nDbE)UTiiAi-xm=GX}-vQ;tDX5WuOz{V24eoM=zv9<}yMdA#a>W z@JU`&BiyE3=)onGDff`<))0pNxKzrjlkt|gYKUs}TcuO>)d~LUdS-@eg%{s?m2={y zn!Mn&Y<4fGjoPrxemIxO3Q@Esl8Y3niL0N68Nwm2oInjOGD8(GX6QTUJk=sN!G{*C zB>mbo*{AGXVDAiv_-l!j*Np??0P^KQHwhBboqWkv%1(rAR0UC^1oAGsAL~mw*{3B@ z_{)eAe@Ft~9w3$ak4-JMqA*KwfKCItB(jQW$L87Ht9at-ZMAzc}*b3>(UOrx9K#9EeTo>qR_MkAK}77hH~i_2CUh;soAE z1>P7ZnMo`GUpXa8;wBj48KEDFJeO(WOEO;dmvULEN6PE)Zr}_r>x}l7$q4I2p|A+T zI+Qh@1a69jOaA;N7@5!{ZKgUVdT3~A<@J<9oz1l)o}%R?+?8L~Yo z;vk~Oz^0SW1O1vW8RpR*U^|e&cu2@V%sY}ug4jloyp3*fk&)ch#E=jK35*bDmeXBU zP6jB|65S)8S8c}!6RRK9D)3!*9sT;7dk)`q^qY?kAJn04g>I?RuB=Kz0dLj`MGpt2BYGl-j%$*m%k}pD=7u(ucH(r#vYO16l5j#EHzyXkl7hH z`?^DbmDYYBS$4CLKa$hI62^P^n=Ah@r{J&@~LP3#{LFfTPamX0g`)AL#xZYK0A3c>sC|3}^rm1=9(xH(0)EQ<1 z^%Wgt;bJX8ye$~54tG7r{3AB@YFc5CjA8N^h3mHh+!(I5Gt62tt`WJFv#-EhqnK3o z1ACY6C+#K46?(lMdNeoL4hYqQoKZeql*y-^Y%X0g+=4%{RP^+I9;i{vn*BM>uQRFG zg8Z$;foip^)nAGpy%-o_2}C8j5vnRYbjgw~+%5IrydjbUm2Hu~He$pXSsru?h{U|6 zlk?hJr_kc{=m)E{_XSA1zYG=N7Yguq8l|2=jXdq7n}BvfutU%)k;Ea`@a97ZB0~C)wt6eMc5`um=@~NEw zJ43l5z$a-NDjJB}<}n0qTY-5%vbmzGzify^8KVAAIj|q?ACB*;=s{^sg{YAYcK0zE zZN>}mkE-X7>L5LWyN^GD@1Y#B|FsZ}D`X<&4Kh#V7NTLGqvCX`S=m}UDF7v>IaLt{ zoA~Ju)hv919i+?B#aJPK>W{Y8=?$anx#;lXL_qG++c_e z*S#PD%y?T76X(;R&(Av!=t2E`F}!xAM0GO1;)^p;qDg z5cE-XB0gxZzMc|`QE1i@wbq>gYRzwnR>7G2sx`*oqYy#jT>D(VD>U<7O$N254o9bm z;)+JRkd*-;*#bzedGxYV>e@W(o$7m)_zFMY!Mg<$7Qa`!xO~#+n2chRxgit17ho|2q7wmu zp_@T@dcO_a-4^C*q%DY)5&&48xQ)AwJx_9-@M9f; zl^qaPvi)6{jQfJh-8OgR;gaR@$7FtE(@L!P2e2fgiEa62{`kzM;dS9sX|^4W4+w|E zTjdIcW){a4M#$CZgWko&ROGlKM&=jEuEFUWD$<5j+l;80HHWdiXN?NA1YP?lUI6~5 z5=j-2Z1+ZIc@`-SM%+z(CY!utrk^wmm-$JkbbW8&sPw4xGF5IxD|#>_$PrRdUu{QI z;;WS=eZV4>jH#!WqR~|T(n6I?7Feg85Fb8zp<#Gn3Cal!H3x7`a}oRR42?gP!B|!3 z)h*mDo>O(m)epmhB1sClYj5KpxP10bu%EY74q_ajLR66gp#& zUZG}QO)LaDAcIon@?(DWo@A*NkUc@dT>B6&koUltnny-dD9ym9B&U;DD8>S*)72)p zMu!VBOwu2oEMNd;Yl-mFkpxPPP%9UnU_7QGc?5psJ!!#tHJ9c(Rr;Wi2T^N9uByx# zl{TvPw^3qeC@@S}%k&YP?mdT|R|M{W1Ol@+2j9vfE z&@ln3jNY(Hvy%%jhX&$HC4s~Bi$;gX1JM@gJwyvIE<~>|28TLO3MR*R_SZyJN}8tP zB2IbLIY|*P8!kiHQ%#2RCzf zx>j@QHLEl-q}*bNMdpMfYjYjSC^^e??M^KUw7ABns9Q9c%`NTrl5=<5gWSSgRTUat7Ky(!mj!4wveEv;Ba^;aBU9Rbs_4#$ zj?ReiQ*Mt_EBx1Sj|h|j{|Y}}R_K`*^$M+C9)56x>q<*ebVf#WY$!r4>n{)W3nGA1 z+$%-^?qMB4fZL6G;+qC>bE^#-89^M7qSE8DruvXtv+1P7uhXg+;la8>^T@D7{7B5O z+T!3?28Rb3jT#)yymr~3`^&4cfI9!Ns5wau8M;md*_c0hu>L`)hBq_(G@0D|tG4I_ z?xm}L-NsuU+t_c7P_Y=HqWG(ia81!3yvyzZyu%nM!0%QZLftE1e}4RPAgBumoq|5m z!f|}XOA5N|9s%D{zs*(Qy&+ZQ$?9NyU!W;ig-;&1Gc5Gbepa~^`NyhIF3Jy#WX1~E z&Q!UFbeS@o`AhHT5jHl+HMWVUye8&oklct0qg*M>yAcFl@Mm6oS2_;-5u|1|+0zS7 z2uL48oe%6Zd<7{- zk8ke+-}8Q;00`JAH0zKDL284 zI1?dV1$L_f>CLgUTYwEW2}grQSBwX0t`FY8lRtROi6OoL7Bd9+@H@iMP4Vf45M0Fs zuga6aZx+alPz*k>RyStJ91R8to4|WOX%h^S&VhLFMm#Cv2IWb@pQrY2Zfo1J_q4#L zr}u7YYumi%^nm<&^;};LWdi9)e#1p5ZW$(V0(E>+zw%&ewYv%xb{qc49+=CV= zp_}Xr;CBOLv&#fa3H(fyat`2Zl8&A5{eZkLWWW)IRlBJ7Vv5SX0J->X$BrLf#NUBz ze7AGQ_kHEVB^OHzlOpuhB^Qn;p`U-A7o9iX^c9{L1`s4q4<*pEifi-atcSw#%?w33!d0z5{>jN*oJ3vdlQP0y(pgO1B2osQIPiSd|1G6!&%oxCv%JRsz+&wbygeb4ysir?V4 z!FQ>?Bnx?vMFxQWKOV_jTiaI$1zKC%*UWBi)a#p?=d2#pV)fU;-;VK{!kXLH&S@E; z*Eh7xUDMti7T^beaYbZOOIu<%{5^say~nsd%&b$$@fSgIxypdb=m)OxJ|KQreC&#% zUqq$i?{B`&_kNEzmzIacp+x?(cbV_`^{z8_tQ$804IQy=Z1?bCJ#&WDcaK{;yavJF zty6mfN~$+Zp4rkcZ~lmuS(DdSm!Mgb(bSze!yB@8?#^p`&U1twVA;6Tgzv4f_Gku2 z&<|#w=eGAj?-9F+eg)TyzPV?BZ*V`GV@oR>F8%|(M9;8H{NZ~MM7g(y`{vqx(ig!O zNUBd+4K~WNRxlIWx4F)5vIK=Om(oMIZ+7qAo3G$3X%JWZ`wCY(Ggnsclgn`=$c+Ta z9iD8E;>?iZ>womv=RL!7$BYsFyY3c_;1X9VI{Ez>(TVh9(TUF;pYQm-EkpF37evQb zFNjVcyQ&wOD>l)I&mEudh+hU{Idj#Bvm_r%=kodNAaN6=02qiwTaYxEB(HcO#AiSf ztqcrp2(vO3?p_&W0-+rIss$e$C zx?yAsf;?-Hux_3RI=l$x5TpV#6mhZ|p{j&63qB3V2Baqu6;6W_$>3tP=PzVvgojB% zJgW>5zobJ0O9k}nprABH6Ehzlgp$Q`)KCibC=1?0)LVOU{7LxF-mOsM9j1Wa|7Qxo z2Ni1R(Y&~%tgAclQK+8Q$+DAzxp*!(Ev@$>yhE)(lLDCJxID)D14c3yVrgro-IQ0s z>Xkce*$zlU=9C*8**1sVW|BLhd`|7}%a;rPM~=Kt_|JUwSN`8l;UBycxgw$Ns2rkb7BwK3>b)Q1EY!D&rg31k=mZLTBW8yX>6i(OiF|SjWwGy9l?Q8O(+VSRyJw-j)|pN){@vII?k3OiVC<*84rwU1OlO9E{nXy3nM=nj9AC1m`ESMd<*2g%#do#P+AVEFQZ6r z_2swUC571flwQ94E?-X-N=WlXN?F%vt^@Cr?S;&0DhW(s2(HN>C3k;Pr#DQwNXdiaE|HAn&>M70JfTaajp zRHuVqJU2lYXa7g~fcLzo>TVP%cJ5PR_r2`YdbX0IUK<32mehLvzYSU+D*DO6SF4~Y@)jTN*+If@Pel1FR7$ieNoLAHabw&VV zWMzM1s&ASzr>WkQ8Vu8m&B4;c^J*I#Yv;AhoC!Wd;P*Uk96l%g66UZH#M*S^%h{CC z@wt_=T1ql1lCyrZl9X`UnZ3{^CZXXGNwKj>ko1>-$2j!VKy9O^ZqPRMd&&xA7hwhhkxek{&>!M+0YKnq02il| zAUT`Z+)z6`26VC5N$U0e^>=^D3U2K1yo_Y+GQ`I5QB1@`idS970g4yg+}oL#GwvjJ za$;5i4QT4MP*-VK7`RH&w>R~Ja$j-x!Mp`xLy%oM!cEwG8=fChpLb zLu>M)1Hc`Mf6(Np8r;55kK3F0KGRS)@qOMgMKSR{8r|gTPL1MNhI&jYH&`rwFfo|}8y#j|HGescGz?UkB#*EZm z8jenf583hF@p z7K|*=2Zx&!EUT_4?&vCMxC2@4$l5((NN1-Nl||ZiSF|TNCoG#cZtT(>8>;dP3$56e z5E0Ruk{FfHGGXd-Xaj+h_&>e^|Hr)^ILQn)gCLKDD*~?=`UH?!IXVFb#|Rmiy}hAu zlbHnhA>SvxAV2PY(|B+)AC_9l_(4WjZ#c3+ zAisU&*gLyMF1ml)Y#o%X4z?JAG^IzrI==le{5Z2pu6d*?4Yj0KDP#OrsAY#&93GXG zozsz7-|oopi%TyqnD*E$<7X#_sQm*X+9pKGw80Ox6je0T9ti}g-Pk?db=j)-79uqS;HyKeyX^*mIL$dnAMiLJSHfqs<3KK zSwY*A7 zG|+BLSvsM9o?029k#h=peEGN`@%FqVyTKS7_G+X`mRp~YJMH#r6sML8Z%}IR$0$9i zv9YnTFm^~4Bh_aOlkJJMFNztGn>RjIT?l2Ph|GO0Co#LQl4X@b9@ z+wA0(0I_e0f8H%HV2`>zf64pD(&c9RmITL*jV45Cfa;^8b{8Bo(9sMHrL%lx;k^HvP>o` zBRzeYbaW!=r_Ysfq?f`K*K@R&bbZ$KzU(5b5e&c0zGKUEJ9QpdhHe< zs5>l%EY1?y0~Y`>S7@h*x&sXhH4r>Hlp&gsx(XwC^(wpAI<&PezgVAVS(BW5XL?jskzru6$VwR zt#QNZGBVLU97on~wdG{}HYu@E)pz}Nt2B?P=X+WrR!nGjU1wAD0bXx zNQ51?@!|y3NaL#W%D2Q62e(%&7~9?o=WVt*-&j##7~R#xvsrRgEMf-!oBDtT(!2BhE@ zZLKmEVpdXI-AU@u;E3EbJD5Do*-#}lSf0nfhKHxfL(MWG>v*Vi2Ji-Cly~=|!7#(IJ0)-;tKkKT-zPx>aXmVhDx|8mMs`sgcg8Z(7q{IWjvwKDQ<>=dSxe zjQwLz7)aL}K$if~QZHOU%7YBYB)I?cEq|CX#aB^(`xqNlGPJ2^JBDLyAB zzE&TOLYQjg5Bz>5#2ClY_z8z5f=f*ZR4l(HLFaK5k}XsQ#k+R3PQ@=!dp;e5)1B&^aQ3e7 zT=kgevl5PuMbTUObOf~`|A}K(*i`{0magzZ&^dG2+He{b;^!Z!kHYfSDYOez2Y)4v z0J=adB;qj(`bXmgYCuwO9`OWBX#^e)c-#C?=Fhht0gPh2iei-e4N%fs|0Qa~iw>`4 zPXV@W!RS11o2J8h;lBYtu%rp^2DT-d&EceG6Im~yJ47fJ*ni_k3ieJ44`MP?^QNt@ zt}J^zK1V~k$+ktg-uiM&$sJ4Pju<s>hGL1D#Kc6&uU)j})(%;IiRTXr` zHz5f!DIjk0FDZtS_~g`t;_~0iD}FDlFV5S4b&Jwu^q;4e4JMpt_L#WzzwD?jZ)<$C zEi*~ZW~OH`GJ9N6q0Q3L-cZ}{W)X6zLb(`EI8VRmo?gr1glK0G!byeJx<3F*993F`-_QQ{B?u zRyVXZzq;^7(L#q8c4UBalJG}4Zk3h+Z^y%lM{!UEV~qk*%45hNLW>LttWI={v`o+v zM3uNYKSHR{@EAhH1?``| zBe%GdLEB&_E;Tu^0=!V9y7dC*N97x&AD4X6Y<#@DuyaYCN@fdni$Bu^g6v9F1sItk zbZK0dW$*rWXOc#)XD&yuMAC_TNF=gX!M@_-#z7XmY%ilVJG}xZs3Cw0s80mnOK6@` zh@AnkHL_QI_P0EP@lz`{6y2MYpvn$s7l-Gl+fQbV@7Vj{y*`_wV4n*Ouptrgu*-?D zemG<9lc>j<9DkhXq=!aE;az)M8s0#sL~(-r_9y5E>}!&ey({3k@4Kf7#GR}WfHtMG zEbtPVD2Dlwq+eGAMkd=`q^UmpP`01nHGYbL37Q{a3n&a`P6rnS6s^$vSC!AWYjM9l zDzJ$~*t3M%HVhlF<~NupFZ%lHg_*41|GKg>*P#f}o)fZ@iRvqWf4g)m>4$jVD$jgT z@&RX=?p0J_d!NZo43Jr{j_5a}+hNb@&+a{|oo#y#Eb1HVyI|I?#hnui(^86-SMQ#X zn{x0^PcB*Q-L#5|_cb?6bp1;lyUYG*+t~K1+FQ~}i&J`-xf4fD$B!%ln&BtNo>kbB zOZKczmEI+hF~HS?*RV>l8FcaL0rkzGb+NGTgm=TkIB(@caQa<`0DU?<3A1NGbrUW% zDmHs{bYaPAh-eXkk^yn-H=y#{)G#UIBjQRKi|@+i4y zI}i1Kxsf`+b&Ax1t`nrnUh^XLW&_`qT>*AkW0O>;4lD_PnFQ?ZQp=msh~j1rE)@qL zDMU|e)rzJvG`!DKO*h48VIuQtGD0+1G|A=XbC#9J{OY}TSQrm!Je4TEg^wB{UM4!@ zbjMW@Cl0k728gff6Wj9tPYer;^wzTNRcQ>raca$~6C;DpV$+m?Wd<)v5UD|qo z86Kk{1H`-VMa5QFT7r?8mPX2A-)gIy zfb%m8kR^9oba+s4G-Fq3R9yAbT`kjhHI+RUxvQ*=`K8gBREUBY8TzZvVd?&|5E(DV zWwd3Lf26B~_G6fG=D*wp*uS0JxBb4$U;O}J{yWMI03$7r%?r6?%p>hrJ>A(dV|P>8 zSxcYxm7JW!)+5979sqzAZ0|qVQ`Z7yCt<}Zhs>qu>R*(D*hUVh@B}__GRPAv2?jlI zA!M7NYGOFum;hVc!DfvD=P0pR<(d5GNR62PCZ>2pp0Cx_+T;Q0=>c+E zoxCj~Otfe|cB_0SQ%+Z?l`16@&IU-euq3@8h+mRsh6QaL4U6gl!R|%%rBX%I_9%sP ze1vyFeMa44mKk8ddiszF{5rd&f{o_hg8EG)E=+ERQc>iWdn*jb9>BNXCe`m7i9bg< z)vlkIX9$kKPB_86#hA$RQh45}k-{(cR_N6ox1p)GJ-_D_=9ufl5@hA)r;H@;+G*xZ z@XLqsweqCE3xpHM5Ah~>_<|Hbbl;;0_qoTsiO*)5LiC2%>dN8sb8~XDQY&UxmruTT z--V1&MPlc?<<)3Sby8gEg8Cs`!<8;oj8Q4|)8&+vj4>$`+R9RUmFY)%@QeR z>YCa{C7=wmv)CRrVKm54`n8kjAMCRLBaQ78;J6Wt;(NrDL;v`}2KyIO;pu5PBje&? zW24eXWTaUaOyA@%s=~`^o1Mui&RNYl8O+aTEBwN>a#kMbNKPu#z}7TpYFJ1~foto! z=Gst`3^6iiZefu{tJBAfA40;+CDrIR<|Du%Y_TC4hW`Pk<7;1fQOJCh7GKq+zpKht zWK$b5tmf@|UMzLyb6?qYYK0#cxo2oy*2NT?E_v>R=1Yf zTVRdMur-HcCd9^MM25_sw?8*2ldaEG=_2aZM6HO5ozq->aOnzjB%eD3YNe9AE;4Qv z<&{i4lzmS628r3efzODyf~h|kj6r_tN_?llT+~U#KG(;oLYzc~4VN5IZ$@Y;jNysF z<54;jcf5N5kICf@O#P5;eWrlxNFY1_}uQ{w{2*x+rPn) zWJlZZlPh8h0Tki{q zLHl$Ovr(d14?A}Qru8s?`Ey1ZxOUuATQYC+@rJqSvsqd%wZp#h8~2(zew zran!&b@m~=K&h@*eMn;B64Uq~q zNUn+~ob}AfcaNwE?8H`y2N{FCS_F1sG$f^z1tFvJL!u7BeIUTz7jlwW2a1ZuN6mi! z$jp`5sim2*3F{_ppW3=K&FZjZC{yc4&+i<$ZAiwfXva{KRppquZ5ooi-r}z|UyICp zx_ab+vg%@+IkzxpWl5Sjw$YlDQm0JmZto~JSS+$2DUvJH5pmUv@yFr79#k$?vv$CF z1li@?SArcBk(rR}jf~_5R)bjk{Fys_CaSJim{sb~>=W3O(|0#>dD-yCpRGzjLBy$kpCRC2sUl#*7bwXj5G%2(* zN~h6;u1cX z&5pLV|8-!*{S^c1f@>0ExCCvXAu+2YIpLZ2Z-hz0*RU6gJq&&^Qi;*Mn-4T0Z!c+h zdr9mQ5$Sd-dpK8@oPF@=Xw8DL;ijA%lX=_%&i`~-68;%%MgDEyS#kN1holosYCm7kF%?otZN7tH&xhD;pGdLm*n8pjBRm^+R_us0mZ zu#5$y_KBr%i=ELFftdFnT=UR)wT1InhnOQz>}br&OpI+PTiZVC)Uq|xlGH(Fi(W1b z%zv$Z+V+waQb=Gd2%tp9w*}MQ+DWHD z*Ad}^i(ZXRwKicOlJ3#r6rO`TR9R3*oh&569mqN+I+j%>r!`cjB+703J14eGwzWLG zYRtlS*CKgt$+UxY$tAf7<7bXpbYa%$7apILuJ+d%?ZcUDd=T!Qt&HA^5>GDLKWF&t zAr-E(!qGD$bBnUls+%WT<7#h9FPi^occH3&R(;F(%%u3733I9nSFKu@Rh-n0n`15Z z)8>pT(dgt*!54;`cNyxrIofkW9eYYP`@vuwF)(x=Z#>Uf@ z`Yog+Cn4Es1i2uP9x|;FPYh34LO_95zBC2z4AEKcIUnCuN815uaQ7Ms`3D z5OE;#JwD42wEDu?)yp4EA9Cxq%H*^mn|4;lyIPg(i3R&8`Oqsb;eT$Q9~0F)aUhZ{ zG#QT_xb5t_?Q3sszx>y(O}C8>FGx)@hs#Sx?kDu3V;|7S1~lSFi5P0)@roAG3k*mn zMAHS)nI9iv3nHnoLEgayD_^>E(fq6;A=QbG1TGr=gf~gy)ybcHB;`obL09){yAQRu z>^jkpI#(~?|3QXA<{>^sVeeBsRS3*P=AwWubf=RQWQ34q5LDqE(IWM1r)t|ru%htm zqn_NcBN#;;xDHW3o}%MtEgMpt6fzFw!=K){f)E8?yf}J1dmUm>={Y<%Ib%lG8nlcA zBUG4Na`O3&kKFJ%p0a=@aj+MFL~&Bb0y{7@KsAEWpc4w9gFNe4Ivx@fWl=vcAQcXx z*~%RUD<^dJHc<+!y}HDnfS&D-{L$=-!Rjs+!kavZr+AlE0^ak8CKup}aVxqTi33Hv z&I_nWlSwPL=isl^;rU5%M41gN2Y~YMYk`w)O|R^54HuBjwxVsW>ezy;AvZ#JbB2{! z7O8D#DijLWE-|91uT@U)oXp!C&?6T7A0%Ca<2u+zPEjvxIyc7ud;G#f*T;F>_doME zcYXZqX#5e6ch`y{oHroqdyg{91=O#=zoH=m-}Cy2;J*-dW!Do5s7O*!3h$t(0FE(g z9q`;j>cBhtP@?ei7tgC5g$dC&q{XL&JT35`R=pi{%_&fZ(xvatY?5;qAHj)`<_*<`s={ zWHiSWbe2YDK}I;e+eEmoRDod-=#PSeCZ14LcJ%%tqUEOE*}tS_)QonzVPVf&ufGL6QP275`=Sjab#-4*3XZX%h8uUHGK_V0ed z10#~?VV-mn{7|3^Jo(lfXyEl(cOqUA!sm_R1%+U+X}mmTkja(A%63Xmu6(hl`W6em zxnRhS7ccM%2DbWqov^FL)>JRY&aiA@`v2>g`Y<5&B zj$mq|tc83a?R@;8YkZL|2hO^o)|#O{57c64sxr=6$E z;H@4&$OcEl0i|sabi9esiHOO|T_xy5VmY&-_&GU=!sshuupN=)79%Ewv@-iDR_N4z z%e3-KAVk&KXl2S!|3v>g4gZg~_kfS0S{sM=%*^hlC!0;O>DiRcruSqM(t9t2Ktg(h z5Nc?lLujElse+1v3Zl{#K@mg{6crm@!E)`5d%gCnBzyQj=giEO6vX#^zfXQKo7vr& zr=90K{a9UrxyVnySC{9C`Y{ZC^0!knA=yl(+RhKr`u_lh501>%Pk^b%3!1+qzAs%H z%s*glKrVxqDN@uIuMoh{DCna>l`;SL$We3ID#E7qN*Ji3m@78+F)q18`Lr^P*-Qp6 z!TQQp$dpJj@t z7B)){z*7yd5R1}8JyV1YFoEDO9w#YwBE~0AQj||}Gy0==6Z3F$M_mG$Goy_4WoUGTq~;+fPb>=A$hps*g8?(&oqKNX0@bnSkp;4R z{+Mb3K5P3s88bt&^Zj!mD^F+5Am#!5<=Z!JzJok6k@bsLuAIfcLUKMKo}}d=9iOP% zNnn8)|J*UK3zWcF4S_{QhRbLH5)!^3=1eSfUGtWV)R*XMkS^|6JBM$*d;$NPYwvJc zvHH1FtCu@>;P03OGGT_~2T0+}-tfzH2-Zy}cpSO1Tkl(pSv0t z5S*SnBHXRqrn$5bXAPWW!qu-{vo#Wb_u9MS%#w5G@SUvK5zU3;wjPRJwFDnEA5}u( z1z(*z0rYaB6I)2kQcfvm8vYUjB`&HoWIihcD0gDsNGtrqIesY5!R6(PMn#6`JiMbS zg7Yj#jK$BJO&$5Z=Dh!l_`m#!ky*2Hl1pQQBKJ*O9Q4o)lldYd9W4(79r-yj#@H0G zKK}K~K zD2aW0@6`4;GS90Ww0wj&(BAiaChM+t2$rTbPJH~4O*VG%`hQW_a4R(}2*(036NVI-Am!s6e{pM*$hjN=Cb#JZY_3@kBx4;~J}6XYZ3IEo{P6 z6)1Me(`Q#KKAt^t&52g;y521{Md*#o`17E!>|e6VLlpk9$OoVKgj_Oh zSs6@V={ZVZbK*94)X(s8Dj{76sM{FEpN^A6Hcw%E%N>Nfsh^{bm)Y@Df zV?PA#<8iCB3}~N9P8Z=N7s{FhsSxQNuONyQ$Zf=e(4K7V!*c@Cwmc_H`OwwSpi`=X zlaqsDd_30I)V2K;Tkt|tt}wRq7FZ?)2PKCD#?@>Zi`ER!BH$6&$FjFT*W8^)-~j`2 zJZ2~Fh6h?-s z+hP(#{RV#1+;id}yv`}7Resk(t_DV~4Y9OQ zy@PKzx3@Im-*U%1?b(#Gx%4~yb-?PF+^pDo<*IQ@RvwSOpqu3lri(Zn@AJ2hpROv1 zcslw?kH`I)Rp|0VBN89P3D@^s&IpgrX?^Rds}~DnVsm(2a?QZYAX>dLw5B5gcA_yP z)V_g|h*+vPh*A*}IdDWu^GO@0-p7k7_GzqhT|m#xeBylXGURlzzPu!8WaLSFuCRPc zb9t_xch<oFg$WIqP=0e|1v=fDQ)wPypw^w)U>e=%srS=YDP}+$cp^%51 zdxI+V@0jt9x$z;+!{hGKsNGc+S5;*yS8JOGo@?zoIKR2VSGOj9@@TPV z8_uL)Z-Pw)^Y}H8wpCLgp^byYE};#QE&)R_cL0PSo$Srg88E8ybXeeT-%ZaC4pA$; zJSKm$V%FO7?6Doew9k1&vR3J_IJ5Rs(&2o<+vlyfGc+SJTwG(XW|qzym7C%gR7$&% z*Mcqry5VG*7U&iOe?S3#jV#mh^>=HV)~qAa*3C@+7Ni_#rU#5gnXYW&Qn(8;a-|QCC?w_3e4yjvhYCkoQAVm*J0h z&1bqQLvllk<1*YFY>*TF*Hienz~A>ME!-V%)@OIln3$@&5asF|_d))s?Qc9#S#xSA`AKk7rUZA(6cGFazuia3CcSXW{j(T0{(^Z6Ov<8wrb>GNVDK1 z2np2qA{e|eWcDRcYe{KlPA{053-E&HOHE`#K{7>`uv<&7$iLVXiq~$y`Xyx}+e6}$ zLv0XwvG&!%J6gGlzY0_;Mp>T+p?eQW)wcop%kQ4I6C+RwvxXelfvIYR_Rfx zd&-ljj1Eltmea!^n% zB-`8fC$k%UEaE*~Nc2XKSLqK>-vj+lL>`2!6Rcjcp6ND|4!BvHAsq$Y3ZUpgkR~Ym ziGLfioYEgwMB*3gPZWEG<6zz}~}CfqzzpstPvgzFWk;dn(Yu zt9@=R`mD$L`pZ^}c1Gvau+{9!{)HGv#uRE};{r=3p(3Az0#=e&6U{9X zM2NN~cB*JN*pt)%bNKqMhQhj0RVliL=Cs7gEuMivuPYq3ynN}tj?xgNruhJuO@wwkv?~ZoKci8+^3{$lvmI^I*T%kk9as5u=rXq~Dx+$!3mlteV@sebr<5 z3v)k>IKlHB3kzaUUTVQfM>%nmkuC2NuLhs^6O_bsJk;4V&D2R_do!zi?E~pR6h`Zy zuFA|db&Uz^#5aaGpP6qw*gq4(ebgJHkzx=SLnX{0-`Lc`H+aU+KR>K*Z0>|fr)5=% zW;CM@ScnMAz30q&V68Te(N2)ih2Ex|A$8W5Nzr9<3W9xjK`r?9t6R`X~9wuxBKV zg_F2&9^+uxQdjrYTr-UjOP33o9U15C=tApMsNK=ZzRDi^JI`icU7n5G&7#sYCXHGQ zJLu;AwI!y{WxhQRH<;h)3ADIKC{k)$15vFPicB|1U=87{E!c&Dd_(%zvwt2Rd0?k;QcOMTEW%fh}qEp$Rg-X_ODuMzkE zIKFWG!om=13#l}qxMOEWMqZLNm*$^YvDG2K${T8A6UQ}nC_SxRVQXdXOoM$W26RXe zsqp2iSIPKPN(_)$!)^;Q0!8S|l%jU$U1c&53T9lNWQ5u~c=!;UzqDxt)qEWydNXzl5?db&wmE7MI6n zSi9FeqFk1}JSw&@DkCX6KQe>xF$YVf5|ArGF$cuR>Ba_}gF!S5pJotuG##ZDVW43j zhnR#^f*-!EXKj?v?C$!psdm!3GZU(-3o8oTZS8Clf`a3!a%(@lf9Kvue?cy1PcYl@ zOx%NioEcA|DIHG3cU=(i)!eDwicb4S?- zkTa5RbAl;{qF_OR1a;wr4VP!H06f_e*oco`{+jcZjT%*-a3(Ql#<;znfw|hTem>Dh zI!?89JbifTc!v85e|5Vy!h%al%`f-^xh@qvVE}eOF9a{$qPsCP5H8HzCmwqkaekI?|Dd%Y(PeqFoZKVaay{L`H`cBiRk~u? zA@0>jU%wm?Y$Xd0ii+HKV^n7G#KPogI5EScdQaP$qP!DiUysK~mI`tm2GL82Miz>| z<#E*c)51hCZbGO*)SeUd!$e<4Bl@`_6J@D3&yP|kXC44nuWK0FymaYT_-i|4`K{~5jSxtA1^KQ-Z`C;4 zu-U5H*IU@FtGUgqSnJ4z=p}W)(zWeZFSV`BhDa9WA7cLi*fl1QL)sK1+Mub;L1zCD zA=E!W(w0e7@wpa{K}=)3*>mBsz%zc_!%+QF)Pfsqb?~&Mad@%_ zNTk4-^eUOr+Tt+-;9JdxYu#n!6bh%)st$}N!>Wcsk_@0izmN%3c$(=5D&g8p(;-w$ z8ejMM84R+TDa^6LtBec+((pWykvs&{z8Iv*Eeol34`!sdZV=K5ePViK@|I zBeM<%CRZq|!))5ap)oEv_X$^<9BUVMkCezbHZmw7E-1r^vHT48*?oU4dC}Y+{I4_z zXpLhyl2`{WSfd;jzV=@3@yEHHPjLQ$WF5z1B>f!xz$}u3FjC$RI+x?2%UPf~?SB>W zDpc_JAO;_pGLtw2UxH9Cbc#qn7g>P&UOD{;XSpFO?nYczrhN?@IBK~LeYk$+hVRD* zTl%UJ%@%piuj4h2dww^psFy7REKk5hWH^GD4orgcN100sD_1UUMDCoOSwW?WJrfP9 zoe4N?=Z#MZG6lU^TB(N5pY!^OtPjvX!ki7}hBoBq7(L&-sg3F!@@&XU;yU&;>|yax*9lrj$QXc97X3+a#{yrPR(legQKck* z@cRa#EgMJ02NY$3GEU2arbu8)U4{~$q*Cc3 zQ-hf&&u^SmIeqnvf`3(a&u4m)8bbo2@?U&Z&s;dH-(d3);6&>gr7LBnFta@bFcJ$A zh)qQTn95j!-B1VMNLP|XG5+rSsoI8z@xvbTYa{PN3y|CS!H3^KI{3?XZhi;_3Fn?X z*6b`p?ma#kgEPT|#*D-t_JaLSa&rAlP(3RIQFfKtOYQfxUo#fAIzU-(|h$ z#@E(AfA~E+^lv12^hA8weY;Ac;>xz|DGo2g{nS=k!965(R#a&7L?V7k`^rDW3Vjf zN9fiwe;##{4bS8AvMej;kJV7=0yBKpQ*}{t##B$NpSJUQmVPz2nAZ!pZt?mc2X}Gg z94~r`kcMW{siCZc!{_4Cp-s=%83CVNR8rFGq2b`Pc(VSv5`5*mGg}_my8NLXH-6Sv zvHNk(j1k$$<>hT_?nv;#tM{*+zRde!{PXk$&upJN(M`5!$j=A@DMOh z^*5jw00R8|%P5gTMnPBuwL~@S8>S$jP631`A4Yc57aSuXEF;iRIO6dKY!TRcUgFGd zlG`(aK~DGtI4F-zs|-{LY|+$)xsxA%9Q~$GL={!e%D8v7|9oWq)cNzvil(+zwYFz0 z>1Q@i8C~F7J9ft0xl02Pn;8@2>m9gz%98GvN7k&Il9LrZqQ1ByswsxZ8`K>x0=_`} z7HX^LyeLX|YO&D$gfuTZ8)oy6EHbw!Ux$~96oUIiaqTy z;j;_9%V)pFF4cc9>Ues}^qinTZ>1M@iNCsa<=dfU)Y=9ggcH(D4T z9*(Qwe;~65Q7q~KJ!lW#=DT#FL<<4+lyh!wTzN)VScX*AUmqFCK57{n7Z+*?-`gbF zhtffB*%-dZ+Z8B%1nc3!j!5wHOJJwz#|8#6hkb)X$hJas44v_iZqza2iH&ri*PyX; zLtiDTN4hdU1n&&U7Y{k+2A#}aHt16F`@&zVLoOS#KjF0^0fe-+0l%kYeDd#2^gHico*1aA^k!Pa(bSs z^z+uhT;SVAj9&(%ccs5N@}^ zqOV^(ijlMMvSGP2_kJl`zK-UJ?(455L;kJ2-0kqI0AoCyLwgbQWu_5E5COw!*)**8 zS6&&3gwm5wxr_X`e!q-!WDNEwYw55q89%IF9Li76U1oHD;fi@1=koLP1%0&%)(wqp zk>C*d2d*^7f;`Y-S>kX3i=4s6f#OFvWQx|+3ccgfO+Fqn8~@m5XtL?RpWC2Wc)blu zXdb)%+fbT0#;?DLzq@?i_Q3~jU%HH3UOLpKuybL@xT{mTmz0f;S%=HBaQe#NLo4HI zeEr|RAH04Uxn?2Nl{cQ)?B)x!g_>IS6Ih=x*-6xMCIz)*pan6zs6|O3Hqm^afaW{1 zqQ_?8Lfa)P&Kf3c%co5##_;p*kjXT8|F-Y`?dZ!G>i3*Q=Rq8H=wJlgj| z>go)kG$OsA+Cl6TVu=O6MVY~-Fj2|QY(JkEo;hHpr~GLu5xn5nNspd`ei%j9m+6d_9kAroR= z=(x^rO#mLB0&`~^#c09Mb7&4Ep>^PcNuvLKt$R?c+ApH~eQXORU zMgd}k=7v}Y4fou&Y*CC?gLg;`Kd27{3mhCounUQLfbAtg`sc=_2m1Td&~#^MV@JbG z^D0KE%Ms?SN0x4zShsZRl=;8jH~kJN91UDjQx{cGIv1~0+QlQZ^eCF}NM~az6K?Ip zSVtt87c`>xe5_+E(ndAynme}C&7r21LDTnG+s9*VS*8A`g<~7_|B1J^ev0m=@%R<6 z9o~RiGBTBe`VLLwX*@CBH9r2#BPodu zx`6lxO1plT(7Kld3S;-IKew{yc*>Y{>(_XXUA=oOw3R_^>4Oo~%&w2W!auHy8|$?w zdn1Z?aR2TZ=wE!8P`|4Lq3xT_U2a{6P>cSZ@UUfT+u;1|6;R7TY;6dTh_f$f@J5U> z8<&O~KMLNLTSSk|y&3DEENi)cWM-{6^;+(5f@AozaqZ%7e=~lp3=I<@8^;lh6!l2~bGKuAJ#nW}8= z^itTtz+Qk_arPt7xj``7K%%(|E(1}aY8aee-qhve*6c_4$B7O_>04%RoDjPyD!MzS zdE>N|qn10V9lS!A0Ih8y{&Cr)vb@5Nv%0LZrq+&Li5w?pTLh+;tmw$_iLi%BLcX5y zm9t@>h+OG``mZM1aLgR^`J}}u>7^+(nqa>ac}!VRG&m~+b}}RBXW)YewHQe3h3dZn zT!7>UAMzN2?BJyTeD(tVSS0(NEJAh~g=wDi<;?RUsprm|eQQ=71Y&N!`JRE=4yx$j zq8a<^OGqr{kEhD-wu4WA$5;UqM^1~hi(ci!QoMPhW8&8Vt_$%%V* zT;Du<6D8{G*yat>df!CBPZd}16KPpLs^Y-teDwCa8`e-_s>2B})n1gC_@6Hvn!du6 zgeB=o8)gG=U~_>iUjds7A`FOluZEcNkfK13c`%r~HQ&*K z3h)347p&c;(7XtkTPM<*i1j$*TT+e*aPaEqh$v?bCGPhLcCep~@7VzozK=b}ze)H2 z`UHAVy1d|o*KR-H2i zPT_^-sSB%GEmgbHGnYPh5`7}G&%(RB<{xNp+Ey}MM%QNtTcbXy-GrJcDIRqsGMleqY7jV1S*FY;30KXalE7?Wc+qS^M6FBp%_~V5f;S%lXXsSU(5UhEGQ| zjf-{r1@Adm(AhhA!TgCUn6nkjYDQ;=CT(YvNA6!=nw(s+x-=zTmA0(Dcw9zvX=87F zb?La2@Ql%mC=`Mkn}k>nbVfn$~eI(FX8uI}^-1 z!0`{RD1A|pK%{P zCbSpxHm(fXd7w5VmfAF6#)14o2+@hOJP|`ZUO|yCIJq!aNc3{OkPgAS#2=PPZ@W7< z;&i-*_i%B)EAkZGT-1)Lct`hh{0)BhJbu|m&c0aJe^%|zY*~X3h^{WmZOrIk=JWop z{=W-96a3xFmHIG7GlfOh6c&0u#{o45+#c|G6G%Ulzy-2s09wHUqrj6(aA2ucv{-3u zjWj`kKdeJ^Z}CFho+}}cZY1ePoN1bTe985O5KH_ic)RPP=m5SX+XazL=maIM1bTZP ze$O=N_+ws1Ijk5Vy!b{!MzX>U+Z0$Z)8B&7BODLH_eiFI&6)=*XSC6$1bsp3%SG#P zn8ib~c`AS&#K*kW9Fgx*6|0dt$Esy1(eYJ$>G>CO`)7-C@jr8mWKIgJMG84S?uy3C z?4MyK?%jAG;7QjrXlBEz$CBObZESq1$9YSYt~eJTSruomWVHGlAEE$yI9c&NayS`s z!wN5jhM&UjZ|}oM=4C8H?|V3gacS8VtJ5-a=G7JXCM}AaLTl7n2RPA(_!=!eR}^5c zzXb%a2cGFbb4rPIHXz4J7$v9)4Icy*NA~j$winW{_IT`o6zi|9$i|pAF-fRwVnXh} zZOp8`P?OPul8jlD5kevs5-h6C;(o;)fc*+`+ek|HRifL8hKI1XFv3o-rM0josG27R zJq=F`I1$hXX}AOUgI5Qh3YeBSExH9;x}pbX7H1DW9`N$$11y@vrcavr^T0y_$5#}1 zTDzRe*g0p?s)0uZo=sJRqZI%)wVf}3T}N;rDG+{t5-=dSOS(u%en3jLVCoX6012>} z$i5{+Uj(yMrC~4px_9uYf&YwY!zUHL%^m9Gz{aR~PJyU~DNd<+!u$ZixYn&vR<5J6 zQ%iaVogp|T%*B0Pl3moIO;8^}F zEMj{M9|M)8n8!em4?O!p<(SzydWxBAj;>p3EEgy(n7f8Y^*@-N2f?YM?5wr1=Kgsy zu_T9yoDy0Pf1(LwQmo1ybW|eGF(RWNqQG4$poVS>k;5*|4pLw~*EHxv!_wmU5pFIu zs;QHm%ACf(2d5g=)JM9x2ZRKt9-Fi0i4D)-`wn)mK^^925H1)y#>2`zE#2wkPB?)u zwkRk#JSk{aygwX2i2E8`o2E*LjezsGWdJ*wu_w_$_lz+Tq$QH5CJ`%>hGr1WSXKd_ zBMOf9-V(TF`fu**UY8aH2XFXKs4qd&yLRBOo;~}*DdaJ|#nCNmr1}uP-O{i*EphzZ zZ)e;$OaD&p$TiWK$r008oz@>c_;LOILtsq0J#|nc59@DW(osx&<$|umzdd+n4ZsNb zGVVCYS{&`GHJ!>}7M?aYTWF|SoX()30ZRfdcicF?fDc#?7}kIwbS@hi8}NAsaOoZD#(5a za-rmY4(Qt*5am4Qi)e)xoImx&9CG~B_<(5V1-D?>vC1Lh)&ggGNY|M=i!E$Jxm-Aj zYVjR?wqgC&e|)fYec8yhVWX!iI46(e=kp5l@?QRj zWm&?slt-?6)cZ!1rLhh9wUzPH9CvJf`Qnz{_uqGM!@R}GGp4zsLnv&5CZGeqgI}tL z!*=pl&D=6O%!{}nG;cy?62Tu}F;ERcfs0p=RJn?`cM^28Swu8(;5rhF2SEl*PD#;8 zpUjKKhs2XU^*clh6t&|-Vteu?EE>m;!a;S0!$pORE;-+Gq5h=N+(cE(Lttw1<33#? z^grH29i~Hy`raoaa0Fb)xlE8}ru=twA;CqOWtKv4mCjKzfs~wRr<7&|^c9iw+mHnv zZjEtO9y(=u$QzPmWe6gGZ0#>f{T z-M4G{oCsa>a|N-?mtKxq+Bd^kD|CAIMI(ITHkC$_0vFIT?{NJ92SkgYM}|&`5{y@x zlxDPp*~x%Jl)Z!83T6n!;Mv>#@B^&MVP0LO9=e0GgD@J8_ zui0BDkbjG`R_Rac{Ss|0=(wmv_dCc_qyMjiD=h#|gK5I~%qNL<78HdkDvQo~p} zxHgfGQyf|$_Bs`;LO#xHqAO)uUP_^s!gO_!;tHOg!XZY&t|*8!zq1nyfRj2uu=+I^ z3Y``ek)EGWuw{K!+05#^w1B{fAhlmi%Z$Bq*H@2{TDTm^jlhovLE7qyqdRy*#6xsNnAYz%)kyx-2pPRmij z4X{;9B_}2~XOBMgMt3*Ar<2V4rv)^GPm=F(Di>Mhl;yYn zm12?duUpHfEZc_c9c>b$5>m9<6jujpkW6i3Rs6-n_ zWWQ}0)7gLKlmGtrlQaFu>y7UtSf7A+ZORC(znWpE=%3YZ>}+VC-ZojeXpwSq+w}H^ zPG$yEG=*i<{@M{K+V}t;Hsbp?Kpsh4>IT@6l_I}bf1&q`gfe*sh&b{a48f70EWXKa z;BeJp0G7lKxl!J*?^Csf`qO<4<)fR=SlNbYf}_>yDA@(Kutjxop+PS0p`q?BL7{PV zi^AM4$fDHh=wMBlt<{<4(dh8gOLrk_{M)XjPrtf)w}x@^3{gi#svYceanGUZJ!1-6 z!VZRp`vwO3hKC*uYbhMFr}_};$+dS-M@FebJlz=0?$v;nBnQos_Ofq6%pCFu!~r9A zB(XlckUv$Wu}(a%2m|45D4bI`Nqgz>Yki-ZoU+FGdN_N@Qe|kCg|nkokJ8fY;I?8< z{@^xx=o_(%Vwo&1S^Ak|965CnoKQ1cc4!ON-w(oI$@K77F}x=p!w!XI1n|L^sZlSK zh9W4;;F8nT_$N3t3evh&)*P;pTCGd>#Xr+4veDLDn}rm?*M&^cyb(jW2p0@pwRqxLaE}}xnTNL&r zxntZ}Ab$RmW6|R$Iy+A8=xA%}*l}cH`+-%(*)cFFVQF||)Q!yySFf%vUl4gY)ulAu^Vlc$kq;+bN_B21p7wr< zqe~W?-3Iw;Su&g{CgaF%NNo%51nkGqVTTM=P=~gKbFW*!Yrt*%TTv7XfaO_;hFvg|Y=AK1AO- z_;Rlo#NacuI}ab*zh?XHHHVo~#~kIfaSv~RjN_SoMWrYSU?I(T=*{-2dmo?Jm?jN& zQ1^XBI>wk5#tAIe{DMdD8-l(BTD=JH0AGV4$W1zQA&pA(2-qvaP7Dl5nh>gm-LeYHk9-4OdX6A)j zjnKOc%K8^Ul=;Bi6_g)$p!o@>Has4zp{A3zhSU#|NQUFhTfl= zYG=Lj(tA_=JsfQ6U%@w+;`j~NL3!)n`sL4zd}ez2j5X-V_x`hQ9}KcRljgn0bj1A} zd;9G#qx69#)_eS&-x)poE>x~TRiQ>E2ZxmG!|+cj^(F&s zSuHr!1U?m`|F-M3^6JXy`)ABJqW{kRNN@G_r+Q;z^PCFh57m~{bkmseIuoT_P;|tG>xD zq;}UU^)?P3{!`!Ew`6|EoK9}xvU4XVw8iTWG0cG{nV8H)!O{C{QDt+^=8wJHy;EN3 z9QQz$x8}m;oeO53(uMnPS>L))Rf=y5cz?^?26(6k%2($|bfS*|%Y!$rcw!_YLEOj= z0_#X{N=4|n+W^vK{BKq>q1JqqRDgT;qC-5083ObhL^v@3h=MNLhU(0NI#14CK)}7$ z0Z1TQBgn+Ak}yy|K+bakc^g z@VUr-!ptXL!hfz?eTg5Nb9!nPj9$5~x;VQ6hUV=2y)CD)Vr0GkA3PUsUpf1>YD6i4`X*eKngOCCU@aLxrd zVd9}+qYMEmm3TQ2n-6rv5BQt+jWr4?gv4GJ!nDqY3(VZ0&^%u+Gh8(47mRDWtE>I(l0h|yu)jTS4bvc{HoH= zKE^MGeC>7m67Xh8uX)gaaTf%J zY_K9!xgEj;Jg?DAPRccG)(3IdZ7b5|&RWkpO8vu4byS@`O>9g+Hf zj8yY>h$VYJ*8*p#s%bnAk~Z)!Pz!T*jE^EoOIS{j9;Yf=4v!R`*wXSs@-x#~$zw-E z%}ZXgdRsQW*tTNV%&aN1%N4HT<6{Ew^L{AF&r*QGE8uOvk5=OYKTXj8Ge}v$6zKpU z8(WIACHnxt6AC*kL>Eb@1$3E~)@+a@1N`lx;%l@Cq(se8uU|>wBRebmz@ZsXP@0sy zHhKAd46_LvH^D)kn@ETOI; zwbS@*Uo*g6l)1G{IQhYf<=0PO{LI@cHhw1>XuE1Nm@#0XNp1H<2QSKu(Ko~t_QGK| zG5KpY<%XgSr)DlVeHwXQdJTnNy2Kl2n>(&$;@hRFg{@x;N82>5-qAqMV$#aoxFrB> zJY*W6GM1j$12hE|6XKHKkgoukfuIBlor-ngPah!T$ida+hs$Y1^GoK2PfTyyn!Gby zz2XC6r!ZqgI|WRd?>4S@ds-{J`y~Feu%)*!CX_+%h2o`ot!wgQ^rNvTD zJ&R9r;e-|8h(Y>0OcZ5^ek^7Xr+zaydZVWWJ$~rS89*hL3wf$puqH2Fynp-b2P>Da zsyXEq@N7M>W{b#jcY89<1vuF@aM7b z7d5>KL9KZ`KjG7_Z6D*eV9~K7ix-@T&g<#T4v)%Rz9uV#!uI8t5Wf0t%@#Jw3diC0 zAM2X0ZrinM$20HOEnQjr?uU)NTcN;+$hlVf0?3UPc3o;4ktiHh3?g|4fn_Q&Ducif z*t*BZ$dIzP?_+ zc2n&;P~_-=Zs0%<{59o8>>UqoJ=Dfg?~EQ@LA(j_&%EK;*y%vFI@6YC!WNJ=+UyMG zBXm1+>&Ij)%nf$&lld11B|XAftU%+tEMI+OW# zp1AGT@%|Pzdwws^kA+!n zp1uV?Zme(+d&h6JrIRo_u~oTBcrH}PP~VowEq%O+-*ID24O5Z}5RrkbY(gx%LQ#<%_-xk5u+gf- zy4C|7Ik~mv?PE)-6#4BoVb&ZY%aS{!Fsub5kdxa|Q9r7<)-gY`plfu^c8|b?R7|j6a2|H^Eh-z|7Mh+J(%K%LRS*Wc1Y)#M@4Qv&N8@>> zemBTJfeDx?7&bgXXoA{>-D)V*rxp3;e{mZOzPNrO9p+>Bo7us8<*){U4xJ!3KE~J= zP14eNEBvmJiuhW5u9KYab{@`$RZT`C_;cL0!5MCFa$8N=B{XNes{;&%(2wAcX}gW< zNTHdqXK|C@8EUXDz$f4hYA7Hkc+qj-qHpFKA4}XCI@yij$xV6!?k_xb$rAcpbZ*-d z_+<=5`Q#iqbRPdn9+SlbF(vB?4+XBMuYaiiJqn7jZ+<6x9`wDnq}8ZxfVVD)2ZY** zG!zqO67;2}8Q=9s%Y4OPFu4vDNdhm3R)^KiI|+hI$Nn=VBqW9WFdyM}=_HiO(R38b zfmecpUcc8NDr_x(la&62&=CAiQ_=`w@(H@X(2^dj0~1uREt#NFXF5RTEV+Uq0NJO=I;rFW{B#R4 zVKsm9A$M7jOK9Rw*7&I6-4>27m}-8yp|CQ}K@<0gm^5{z-B@kM%85Dpn?s#sD8Phk zxMHv=NPLWPhP182_)Ksxo$22sY)ZrGg3J-u(`2?ODcu!H47g%C)zt3efARC!@*{ks zkPZI8J6Kgh-{HP7yrYiBzo2094z3|XPURlxAl~TYO-Holpg@lj^ca&g!p?%9fy!Cq zTr|VfI2L$1n%aRaob8iGeCTITn-k` z8@DBILP5a<@^gILmTlfR{9pU;Gy3+a~&E6eB`6i zsVe|dHr5I$^_vWU?_q3*ha7K;v?VJ8XpjF1Fb|~t-vW79+TR2CLsI`j6J$7O*z`jR%r45~L z)U4twm|zw>HMPX}w~&Sb`-i&U0T~1oG>YM{qyxDydmT|$zTX&;eYjRi%ITk zjSp^SiZ;)CWy4D~sebTJR3KOtsErv3<)hc;FSGw785Wbu(C zBNCEy$zo~OpTSiT>zjm)pKf#mL!Dq8=*U!5XXdNatnqmX*_ETU-kwut)+g&^ww(`q zxj(A5jkZ;!S;qfaw&g2E){s@;>7Q0y9IUcDiheklmp&T*uCjKPW^h~vvar%HUuCf< zLxF?4fEHx_U^c@7T(qN?#N`PU_?=ETqY&srTPArcSj?*cOvbbdTUqDe>yUcH)^o3| zv(h3xR^<`u>fk)0vMEiP^k;LZ%HBDZI~`YGi`V!#a)^SWL*uNRUEN)>t(_g?v*Qcw zP<$4H2xR%r$=>V>>qQ}{e%@NAbh|u{!p4$ld|!cwIw!fRKbu9F3VmNTkcsFrN$j0F z(i>1?l1M5#s1IdwXdH>DnAHjiQxVAs7C(O~-z45aLew-|Le7#)klyHOTdM!cTInFK zwUOGp$KsPP?~N}D${od8uIDUl;60s_@0;_dtvNWa{$)o^Z^PpL8HJf-yaNn$^ORfb ztsN|!X`xRT^P0V-GA#|sEYzl!$kj28>l1RNemG{ zv!W+J#!&HL7>y(r2n?OEm5zh(=H@xmb;0Od9;(Yy<8M5(Y#bG`I%}ECx;ZM#2YGmA zT02o}F8xIkw`$~ywl2IX1dfa(Y4#K2=r6u# zi0+zXrYRn>S%62dG0G?$B|ku0n>i(7{)5;A#5PNi&ARi<8_UDabeg-d;ANuZ85<#R zd%`S)PR@uwQPM%(+YXh%z3r%7ihB7rs;buew?AVVN(b2@eg%nZxzOtOKoZ#V*HSev zCb#3Iw5UmNG$>?TWs_S(B$SSn)?UKjEnRW`=rojsFE@{EST{N~bL{TT)vjy}YvWR* zmp@t(9*TTlxd7uzH@fPx&`Y%i*=yS_U2R{xG=S&`@MqXxp!OYpYv@o}N8(`f4|8;O z3Pp6UNhTQ*Au~c#DEu)O>@RUxyQ_HQiWMV^cWH54qMfZ{_)3?hlXt8>a%9!cDN9{? z!<065w{B@V(Cl&ZDr;&g=e6Ut9hzHJjvjf3x6az#T3g$8|E#S?ay=aR8Eg>eljcBe zZKIfe*G-@vg2 zI7V($=2SN_<4izek)xM_PBK`t=*<46hE*^US^rykdUVx>6X;!&u?A4WkYPU5;6-x5 z--3Z7ZDAZHopbPF&TA(pwu~Jc7<$8fRFQk=OB-MR9lADv43wRe8yliqh8whBi zzt{vg9CE-ASfwV&`K2RDC$9E2=irxOiNZiG%Ok21uIsYDCo_$jl*BRjcCVw$~_!Z(Ob2M+=UBS$TxiFcZF=iEFic&G+* zgOc9Y>h^U$|4!B()bgDKSX(4BL}`p|l}r@rcCTCp`jKEP?3u$8P~`t$dR_Vpfxt1#?c%M5 zq?srt{qxM|#I)W`Wb_%;Ox9pZ8HH#dd5|RG&bLwDk#Oc@yiFG-iwp957x5dKOVHipJN-%tK=$O3ik^O7Tv=WyC{ff}I{8kPbC#!Y~Bf1A*J}N7g%p3?aIo~5d+;~)= zM2GIIq&ouG3Gitlw83wn1ZDD%Y#d^u5vFIteV~PrpO8k;JWA%GZF+Wf(FnP(HV0p; zY)gtQ8L?74*Tf+wy&jNnjGTX{ux^M3&K{@AxVrW+s~#&JxqKR`DYFf-bv6>kFfDg! z$4+?MLPdlZ(R%i*}D@z zK?w(Qc*$Bo{b3x`6-Y;r`F>Cas}1ngH{hTAz=3*(`}Sn$hvYMTKXP$*F7lsYJ&fxlfHp@mTL+<2~7#)K5fE%V3wN#%t;xw&w~*jewvaKjgIrx7vazS zkUg^>-~KT4B#%43edi*)g3rh~KwXo9Khqa8`;mR?1Md76QU8k^)Tc^wBo35c)am3`dmJ#$a*-m? zFElh06`fp$z4Ct;ZK*gvWRiSaH6HP%~Xcn4_7NQ=s0B8paB9@vW_=Wpwb3lF?l!zSOwR3>% zB@}Ujge!^hQbi8sQ{>iW9}#kTk?{mH@}ndS9zYIJdT`jC+Z@d;co_8x`&? zmfr4(G8y}3&H zPU@>FER4+WZgIZd0-uzg?(V)FNnYHlaO?DT(@CX&UJX^0G-OM2WWR=mTL$=+dO68& zuPT9$xVy)}l3wR4FBz4TI>&v>6YkGh=ejp3-NXNw60R(1%3b`N^%JgJ=Ab0^QF3=* z*<^}Ni?jqs;g=J;<#O%AK{qCDKwP$agTg)Z&&Q-Xop*6(g|r_4xSiA8Eq#={0NA=C z-3wJJsU4S);91flFME^!MxTR2R#s5StXl3q_+a0o-Q8RcdGY=j_pSiz2=&7}SC2(H zm$c-sgAZkOcZa|)hfdpWPB$*jTdK0!;{S-3igU7e-JyRrII6NVJSZfxvLqr%=CaAB zr@Om!lX_ElclVm=?t1s61L11hiRz+qZN67~cemBAF+R#^J{6vu)$37ncQ?*orP_pc z!wajT&U)K$Mj7ejFxjV6{J8!phDrBPFI3kv=exW0s?F+6%xfS}H|JYzZb)rtP_sS! z7o1zVM{06%aOz3 z%97sx$syidaqM z=Ns7T4c%kZ>FLa$+k$*7$NA)yZ#nAy=BMkcX4b28@-;fOYNk)sr;cwP_1UsJZ(O}) z(4SK&BHeBcX#Yia|G`Jsv709bxa*&(oL=u7CkvCyvwZ@3d|Gb1fc%^VG;asMi=J-T zruw9s8qeD|VWyDUuUpj=K)=Afu2fd|L~l?}>FWmZsemu^ZGjic&NU5TB_;O#`Qqo9 zkWFnJjdiOwwM}TM(+8DLYjBKVr>fNr>Qt-E>iPZegYbL-NcY1!Wgf3zSWmFhpOnjU zd^Fw8Ey1Oe>m4E)1#q#`rw9Wn(TPnytLTgF^`4vSE2h;eWAK+&R^5*6`D$%g(ZmMZ z@DoWs?%h7s6T7?fKo-UW-+LT3F+CO1n2G3gE#sLrk^>L%oiSzOZu&|5OgXay30~SsAMgKoE`a6S8>n!&rt(;GYb3>XYcCvp!bCxJ+%F z>owIM&A_jYNl6()ewaKQt-r=Zp|{XA241~^x*x=NT3wkZK8&PW^u6?BqesI7yYARZ zK80D?V5g~|falY$u3wlgavf}gR_5HGImfN}F){h%hsooALkgLI-X(G47;Yx{yaw{y z&~yfgRu$ryYP=C|szJ-};u$bZ`O z8}wVG2DR(X%Zv^8D%?R1IDn;S`c1QEh4FV`mhjKKeOq|8l-z?&G`WXz@LdMM@r3!^ z2t0;6La1bjd#Z-M>%coRHAZYjSWWLvF_)A3bM0m@t6=uzAnY{)#mQ5+cH^B9z^@Ml z4h(|_G>4m@19tS#&x7hFa%a;Y()ED@>fUHYChkJ<6wx?6?g>Msl$lb`#Pn3+IeQk1Q0;>T|a(4s1=v(6hK-MKC(rzw8pcjFemv!L@sDBUjBT2J%qo&Eg|=#bxh)GlRZ;o@|t7B=jd;Xuh7HdBlWk%SH_1A z073u`lHt5=o{##ajubZnPcq+^VT8%_90}9c^t>lwPbb+1aep^`ZKR0^srcJKBN1Hj zH&-Hnt3NpK1$#yyBla8kg5W}AbrI~}_GY+@f@p>r&rE4-%1g8BCis}r-qemUy*?CA z7@3IcU+_sLqHg3JTPX5uAPoc&n}tpaBoMi2pow@vVg>uue2y8wTSAXXk~!uy(U{1z zDNRhToATb24)^lfR3`3~RwDI=l598NL$`*LPN_y3LjneyO&BA5RgS!IUcg<%nk;%XrIuon!ATa;e|;fK8d zYu*m*p*c{3?>uPD6B#Ew*&{h%&KFae9!}PWyZ*mf1ExGOef>XK8$KGH|cD zawy&pbxm6SSNo8G?ZYl?>3KmOhF!-7-Vgf;=%54LE3+78FB8`}k%_C4f83i~n6B}^ z`}*(dYE%CI-Pfk_BC`-zxzVOD%0b_+;=9Ic##ckVYrG5lxVZL>R)|p|`hFGPHC{8m z8tPr+T@1Qpkc6O<1Fai_G!1@B{Pyts1QQ_$nn9inF9yFQiW=-8Bra3VG_tASOHm(Q zCU^Fa7pC(-vyh7_*0e`}X-x2(Q$NQO;=}aUP6KINjThlP5gKaqmvim({^a!XbdXQ~ z!OxHmb!`|slxsJKL4Vu)Z!}E=%E$-C96S>YOn@~Z3ys?pGL6z~po^CJ1-vai1e}U{ zyml`>!$A6)V`l!Bf%YQ0;&0B|j2HTc?)E49$*_VW`V}P*U&;{ZP!1Jl9Z>VI|UiTy?L)deyhZ+6MWoH0!&EG^H{FU~neo7(NZjiHbn0Y-- zvOuy*vQ@HoXc}vVkhh^|Jk;lgl2uds-pgww;$QK=oI^vd+#xt33i<%f95CZk z{~ohH&EFirHs(WtQTOZ%4dj{8-sWwyA$T;DjvI<^|EtdpqcctU`v1q;`YXQQE2oY7 ztWlQ_P;cf-ZUAHd#+wF3C~gCW4RqKGf)AF*wL=bw-zUiWog-N%*(upCIRdpImnH8) zJ;;!I-cajvD0%qbeD42Zy_?F;|0C}`z}u?M$6=p4wD;cDmSxF9mNjhImiOLvY{&6R zf*ofo3uhCu2rGmDVTJ%H5H=Jj6v~g$GRt0tmf2ETR)9kLD@kk`#tYDXXg2TlMnnDzWkr@iPK?EhIgETMJKa|f5|)k<-=3(kNWV(8Ox8_ zgQvr<16j9aJpge>FG0M~U$VZ*I(~W_`;U0Zf18K>mw3}m9GuC^{!@M6$8hk+p8qF2 z?R1z*+fEW-{{|~N1quI+FX@kdOk?>8ToK!=O`Jt1=`@%p9>~hrsDFakxTA;*QE}P- z8Qz|bU;el6otB1v0xr+Q(|`ATCSG$Eoy`4C)niY^%cI|({QjxWPrd%J_fO4_T$ACU zCuH&o{5_pL{I8#$NaYls{4enq-FgyroPzSFT>k5qPtNCu^?>gi($mE7{YM$40dxc$ z({RGZcAOsLXIj}1ITt+D5}da7iiUU`?P){FQ@05@$i(!Kl$O0+w(*gfENJ5BCizV?ho4b2cd7~Hn0)yJv|=(zpeGp)b26FTxrPR zBc_M{6nZC9%uj`7hLBE$>Gz=eZ|L)%|pkoh98y+vshpKsW3m;H}Gq) z34aTE`)jPP{=ZF=KQ+A{;PW%}l#^)phu#NFm`T(BE!zHX(f&{22Sl1LoWhk)CjC>8 zdr-)Zl+wZyP5+@?cv^ksr}D<1`rZ%m#Q)a)AKVJC?LQUkPshjq+xJdemY+Zw|A}lk zNn@EoJ(yxn-Lcm4{~yl^`TMjD4w}W$Z^0IaBi=LT*e?2a^q+t2P&q|e`qwX?tV;c` zw)A}$%d{f({YM$qDx*oETho?u>Lle`fH->Qe9omDE%fjgz}iIYdI}099+6yt6iNpd zR%7uvX50wbJQ1x81}@r20yY@1h#Xp!KIL5c;e{dJiZjn#=?m?C{=&qCzuk>5r|{(; z(UF~l4| zvyvIf+(|r8{oQxf4;t)hAIyvc zQ%Ar=0$O%<9CiRGJJleBEW`9?=_$1|cu@8CUxm4J($l16-Xk_I7#&;C-R+PUk5&6i zS9Yzy*LgWbHF^5{v5LaFGv+q6nFjRd55ybH;=Hj^Z)l=v0`)qxb0QvvcPyG)F}uIA zmUi}TUbyJY%GPX2f9W!-e{t8)){fu}ZgI>s8j3jyOY+QntQ3=sXU^jsbx_HkcLN20KtTyK70CQcJ=pWikk3ifnY= zOOAvic|ZL8`dRgRAHk7mu_x?z-lu++c_(?lnrK0a5{fvm}800@2Ok5dVJINv6}vo z1#_kj-m&A-rLDJK)i|DDUb(w|$(qz7=8Med)P6RZ%E}|hudSawy6EPe*DSkv-M(nF zd%^8P7p*+Axw0*CPQ`&b{OFu(mK~}Iw+}|6t!Ldnw0lMBq1InniOT}j#q}p&fcjhE zg3HdM$Hu{H)p&9W2Of$LV%LMgpzC_r}qmKeT!= z)hWJoVBSO9wmlSGn>cnUxg=4m{^t6hAKkoq8kZ?2_Su~zavW+aiI zFHZdPJkB_Nmn{>m#)w2pZ`k-YWePUcsrw)10R3I*xsn5Vxx zLjU>GcGQIbKSg+IJhomBLVhr_5R4ZB`pCiqkzqy&j~fU9X5i4m0JH}a!yOMY$9A3d z9ADx31M_=S|8egCvQ|njAmLpP)%Kq>%YBVDc>-%NS=g%V^fVry7?Ci`0 zmt(V%z+>a~OOE?z#X z+cvx0$|-L=BKZwbjJ!`h@ZBF#EY?s{)lpsAxDEY`+4tgy#0AS5+Eyp_h14CPL~`pr zKSRBAFc_UxRp1iDQ;Tl6QfRGCx>CGs(E5Kl61 zqTCbdelNWfBP;nQ%1QmAi#g03?m`;o(=MbyiZ13;w0An?rZ(hY-faUNFsF@q7dhIP zx0xFVqevLx=FeRpE~uYVbzS!#m(>tB;e;#NEJ0t(ub zeWy*A4>M_I+5(_K;&uQ+r;9RWyqh^E!R#XE63Wc?%=+YQ#4L8a8kS4-w3jXen2PY| zQucFz6rZ5I#f&t;NP~oT0lJRyGkNXpOg(z2ojQE9n94o+CRA?*ocR!CfosThK#-#2 zG_Za*@y=<1{lyoj2X_iD=}y2Q7%^%~H5M)&3vs$L!9?+Y0#pTzq!~mdU~a$#J7 zA+RtF5lp_A`u0S_BbbkovM`?|n9ol}8D=BXKq$ZX;#8zb4nO=bPCwOdWAqx}Yta6D zBHeK8$Xt?-=&|Ih1V5K;z+8f#e6^Qw63!{6hv}hx$?eHIhjCL56Wzqd=Hx}hiX%tS zrwlaT3A&L0w}Y{wd;}9huq~>@gMMM?ZW_^%hfDo}`SdIAyNN$|ze*$L3mKp@_wLGF}~S7uVj^ih^0~*J5#)9X1*yhOpt#} zFz23}*9m+*GIwSUEDju}(rK$<4W+C!zMjJA(9C>*gM5$eeJ{t;vcV%wC+9vBx7oVQ z9C3aU{OGaX^8 z4>I||PbP@U1>b%)_}RA$ka6sv{~UYrl1s>(_6|aMSXRt^ClpWhk$RAtR|5feVt|-#0wxCzepV02NL`DQQ{9M#E= zC11%)p&T5nF|gWS1hgqRd1UNZF-}F` znJq0%nUd_0V$#<~%hD&TPV@;?2x(z`#fH>);)IZmDoo}QTaLZgNPL-WC3jGVlb`n` z$NONCr8qk`12n>esc*bc_Xt*qksce0Xz2vHS6?M2dv3h( zu@eBoI^tn+A-xhyYY;PB0E-LH2Z6|i%mFk^C8wf9Idd0gdH17>&z2^SCXz>`XJ4Go zhg$~uNI{x`T!vXOz*t~uLv1@HCvF*ISO4iv=EW$}Oh1!+ALZ-Od&!@x?mYMnF_1j; z&A~fyR(IVPrGAk}+{GOF=)xW8tae-obvmKvo`!x&K4|6MX(WM3pJ!;aGrvvCbK2wb zgd(m84QAH~dH%YTDX^ijLx-5_Z0Hr~lZ0bB#b?s8d?{w0%(Ev@FKs9MoyD0nd|`R= zAo=(C$@av2;^&DMon+H7F}25e>;dwd3~ZC|K4?gomQpMT(-Yq5WO6|?d0!$*&q^L3 z=HeY1gw^>I$?xF*1b*N&K!?brfdyfTE@!5bAX=lumD5QP@s#00#DTZ4$+3107xNat zlT2DbusD$!>2Zsa7e$j7B$(e4zlVKw6hzq5L7Du`OR!}Ujp4n=O;Uo z+lWoXJvGTEiJatHL@d+RoR6VA8EXl23(RaF1ppQ2V~~jG^?~H;iRA13=nYmjg1wYf z5w#7;F6M63N!-IrDsv{9Y1{l6sjAfqu&K&#luFOS_@ zga*c$7m05>iDv`JT`WA0e@Xp?x(^`BW!n&(d3dQq#3fxG64o-;Quccm-17zO#FnM4 z#~%0fE^Q^_KFYx?&qEhS*x#c)I@Ei2E?TQ&ZofMh!xY-`_($9l@>`fkzZ$3qd~fLm zP19Z&>>s7@eu3T``D>J0pLGu$-c2wpA-`-Fl;+>-NNQH(6U|BKn4f|YCFmMU)lvl(`kXi28_F zMe+mY1?C0>i-M%m_>%SmjR?~7Okvla+D7{qFnor;fDkZFYK(CjeALZHXZt9a8;Yfc z`^dx8tw595%QM5{O0s@FL>|tlYT1!vZ;?3>utD!mt7uI5T=d*L^xRx#B9%Y-lv+Zz zva9)m`;~1q?DEGerD2CHw3-tySwbyIgmX*AZV{}UT-wr}$jgmSqB-*i)&i^aRmGRn z@!EzZ(P+8b`L}JeSsX(;Y6)e5bW5O&|0-n&Px$wNfrs)il~B${rlh9vLSKx^+@Fatdff6Ho?Y>UBc z@F3Do`5p_{lhW{m#+^xJW;(#p(q&-NQU5?%r%4Z{FS;M6cneq|DZWyj!X+$gL1tq) zOI9Z*q6uPN@>*hEly)c2Jt60hucK9Zf%2Qa=Q?Z z83YaJ`nKe9v=3PUCto|*b&&a@4Fc9LO-(;v}~L;J*`Q0)BG zC#DbulU9llI{zd59;&@`@{DEk#%dbJx3^cu zhi^?x&dV;(k1bwYAKx^w%IYpHv}mrqQA#BKbpFTzrk!lgP*v3s-ifi!VU1Le`jC^>NS zNUDAC0vN!ra32WnS4#Je05n)4WcyBVZ&ivE!BM0Ia)fq)RSocWv?d&lhCgl&pIthU zQ||P)to!Qhk*OosZyxArjch8NpA!#8+t>Yh@yHmWZ`jmQbM#^SK5;kv^lYA8)jn3{ zs~+x(x4r*d*@GV~9zT2iV0Ft_%vU|TtFGnso69cya>?j8yo-4imca>nFYyBr+o@pAg5IoyXfy?1dJf>F8n_ZJ1%|Ij4IP-^ z?1RO;VvqR#n&|XxxO~x~eaTmo_kv=#1O3meSgfzE zH8zV{zvyz`lO2;|*Cy_3XlnicDd^`+%5{W;*51Fw{UU>bX6 zwkaOf0;^89%Rka^W$mn!Av-e`pZ>>@_4H0gv1wpn6W$Xifjf0?(?AC7DY(P3z-vH% zVJQlWmW+rdpyH%EMf+?8$%>MmKVJUq$lQHf&gC7L^+e*z#Dc2wU6WUp<`9D8YwvpQ z@+&5njuF`pH~lGDys@=$;pDkzcCm8!pM;Q}VEd}lbX0+$8)pXbWD&xpi}om#&bA%Q z8%q{mEML^x1v5|Y+_PqdZW+N<{k*FU?N97kxm3Gc-qtnQ!puwa)9nB+%%1^IaR)d) zU^2zaHsb@iT_PR)L*nuZzH;uwuI#!*IH#wQyjrK*8%xe3w&c&3*-GvV2xY|5`XNH+`8mH%6~WxBHRh zHtLL{J7~A<=rz;^C5D2x46EW84(Kkbp1cd7o$fzm{U-Ita>+OGPR0`q&^O2s@UPUf zxBwUmo)z{Dpk*i~>%ZUt{kU1ZHO;ItY&_jLm|^93v3ahI;vBnLyI|IuzRkA2Yxlmp zdUosb$h?Zy@jF*+?(696dzjd_IKOtdqo{X7{+Ziy?qAO1-7K?~2D(bassG+tS@Wn$DNn1Nr*k z!j?%{n<)Xb&S?u_qxK|!`7E1BK3j-o%-_%xU+OlURFF?mFEKTKEzW8J7vic%gA{QUuw+C#IxVGyi=0pUkHd%%}f+n)xSqWQiT7 zgP?@%NfCp=gmrSB0bmw^3kTpJh8E_psRqNm9q*6{R*&$W67a0Oz=Bw7;~8#W^7hTQ zJ`ukCymgm%M9xn3B$(pFRaYg@^9gj>ink8k^c4H3FS;AuM@$VpeDfQiXk4;xOHF|* z)hULHmF^!Kd?fvJTeXkvZwB2F+vr$#gmRoxnjqDA)rrim$|N!)y;L0^rt0Z~*d_ZZVZ(+9<}e@?u?U2XeaT&rS~_tC^TBZgFq^zx8^ZFX zuz+3pC5&|?mNCF%yy5e7MubO|0yvi=#p`lrHZom=0wTp^+`whiRs#V5P;gupI#rWGTn7lE#T%aP9v*2}CnyIm08X+@!d^p>&g=wMuN)a`N5H!hB(= z&k?Vatd<}&Kgt#Dzh*#Z%+Hny1oGzUsBc#eZN1gtml3*s_cq6?%h8g?^OkoMRTVf~ z(FW6Bdo_jS4Pu!dnY-f#i(O*X=`B^YVQ=N2;}Hl5D-KqV7Vfw#sOR;x_p2_7wsy_d z(!y+HVOsOn7ZB1CnW#`C6r#Gth!jZ(ifi^Tx2S|Foz6chH(5mjos&-}<+Tb~g)Cx@rJhRR`E)5d=-i!h%PfoEK?SFZs;Bt zmqV9&ty)8g&aYA$2ugCzhS-otTA(tTii;Zq1+9DeeqOm&t#lhhgSiFOa+@$zv#&=} zVpVskX(Be&AW||MI1 z={SSmEG68C&!v|xE#V<;vDD(KjJ9=?zs$|o0%Gf;wNA!VMO29Fq$c ztTPGq4tvlq(pZ~m%d5VE5v$><;FUawq(suNNVy?Dzk=otJbdkS%gdj6`iq3hdh|t` z_Z1GhRn7b^r!rPH${bc^UrCRcHH-PVK5d0sVKfMdV5wEwVpX_0VjVW~s?t>k`MJ?u z3gy1=UZGS}+{q^%lp4(?MK@1$uPR?WzBXE>beS!Z5~-_{r&R{sm**BcR7Qhhcu=L+ z7ppbOJ+|)b(&JeHxwutVT;gnM^i04s{#v7Tw$bFMHd_d>JewS^REtEan58rxA2p2) zsJzX)-Nr`b>bpo1kyr#?m`CR3T`uO+ zv;fT!%9wX4R3+v!uhFPp!eO4IQ458bM^QEN1dZYZ%{(PSWgH&!TR95xIm~Nnl*<<~ z9~!_vAT91c2XT)H4do>(CYBZ=clp8)5LRW^tV&J4)*CMj2tqC>P_bOnS7x8nqvsI2 z%H6rSW~bAYS2h$ZwvD@Fy68!w0i8{mB!-`SYMl+a*t z8cPo>V%#1g^(|;t>>4Gk_|a-yfLo9ai)oPLG^T05c8Ahns>v)+rSSldX2keBUYs_n%OIV+@)i}6pMjHRs*4KUm$aK*YM-95vri>jSPmNQITow=l}-O|8~aSfKs zEP9i_sQq|_%#hnXyIiNyJN24^*Ti;8=J>0|Y+9b@#+{Zhj+=Rb+6a2X1z9gIgas{TJE{9DPJsM}=LIOlaxyG!v2g)l zpZSY9U<$tYaZ0bqpb~q@@*7A8OLZuNmObFFFhgP$8$ce+;h==@A*3KdFrgf~0pe*e zk^oyR1oUJdgRcn+Tb$B}GG&RlU2adRe$&6HI^cBEDpIQ0kzguq_=RSXBE0q*yb;EY z2FbCSL<%XXjcsy;!PP&eqD!ng5g99p=sEccWUF;+`ZchAR85JZTcPpgMl1q4TPEak zw2QRmJFNK?ts0e(&m$F5o`f&$sqtHEWVYT;2zb`32P>O5wXZjHJNmg!ttzUe?XBlG zjCFO&T3UxHvy0?Cr4H9fb4&fEl7h-6qeN>E8Tx?E z7npLgSKE-r&bLICc{#_kbjmy_U&1pB#3F;Dp-%~OLez3Ok|Nr&T&FQfOg5yDN)3^6 zEkfEnsDsGPJXG0i*I0@JHlf@|YPz{np|VF;+iBL@NV!?V4dzD8Md*-En5SsrD-?X= zxX~3A5S4C=KwrG1<xJu)Y^7Z1rl4!O>ZOIRCd17~adAU50W02R%)jevCjw8z9 zR6dg1Vdk1`K8;nOvl9~Uf!si!{{l%=?-9AmitHA5zNx})u@sw4R-}@IRptCrP_Ufs zo^v%ZtHG{VV-g!Aaw#Wb&vO+xq+FTBY^#<(E9p|vI+;={(yxanQyN1`xTbI!a1_>dO;G^GddxW8 zA$$$k#$Kn^>%#;9cQLl6KL`4m=9L*r;$mFIY#O!kTdL7T2XRoVwNovXd+VOxyAarp9=CDS10_fMfL)LiAP!a zJdMD{*O>xJfzUd4&PGddr5w`ftQsJl+pn>oFieUccG zca9IX&W17uo|LFKI=)laT^m{_7RdEpyMAL?2c^%8l$6V);A6(~xHF$nPtq4=jb*)+ z^)0fZd9W(nMzkHg5Lkn?AS`%U^9-^v&_+rY~BQq)kU>G1&Hs;(C=w?Wnp*St9FhdHs6PiUm)>OmiT2_Pvi&zgY zMo{(}%*iuKHN1sU6o1ctFnwXwg8hjR6U&j*5l~bO#lp!dF@>AWh&Uwqu-43^Icnq@)HeQc8uwi!igI4l=;439n%4!Nr1A+Hm>U1hM%E38d7V zU=dlImK;xZ$Ky!T=??M;-kB>bMrY|n<_vAjwToJ&{0^JYE!;Cm=bW$XU8$cxxC4b= zDw*~04f1TRQ}Ffg%|pE4&+cZvzM;*n&=u;`l4?p~6{#eqrVZJ7NJ20d8aHrHk&&EZHmVjZ6=5)RFIOW+bjt8=e@M9@2H&Y;CIYt_zt zA;o?04;BkT_nlY4FAw;Q?qY&l=rMR*ZfD+{Ybu7%mrDQP7gyFT4 zMBCk&3n48LMn!&+q^P<4jc{&AM7mXDuQ>^^Xp@hpZX5A?AABS@W|DI_uYR?BLAxMA zzPu-9u9e$`f)S*P*(rhL-gczWlN8AnmCDe7LFm>M1#GHP}~ zt!NI#p+%u=8L6T84!$wSA#>F_nMg?KHG_zHHySkrmD*#EXY-x;zWKyIG#VJp!ukxE zPsl%$H$#jrjQV7G0IYurv{H^(Qcf#wm|CzRI4x6Bw3o3hfnLCs6SNfp$&i2M(>7;M z^7GX`lg}P3m}}xLtjw9}>0(jFRqR2~i-G(jsJtBRFX zaY+d$`N3SXa6CWH?T!ssXf>LtdXJx1T##MTXm=m5No3WF%IZCQo-meQWX>)whzry! z43?v5EGZyvB`DMgBx~eo*@xO@q%T?bLQgXSg)N8h&Y_x$n#JpA* zCeERg+bABfOEf?Ejm9C@5=OGCZ+viYg{ggey(IQBIoQ~x9*nGigBuLof@qvv)uq=Du3OqA9wdLpJeBW8&A0n<#+XZ;=FzwQ2T59sgv=An?!=nG z!FkE+vTxb-#_Ncza{Hl&W$f#N3)WseUM#FCtRcH3(P29YIEQ0}KB40DcIY*9f?v5E zdnNA)^77<)CgsmLPY|335xt9A zcRcH6;pImbBVyKPyM*h=#mZS|TmygfEM=Hk|DtLA-9CULpBAT-mRt~q*6qx8)CC?E`toiX^ zFwff5+&7zdjdxh$+4)UbRityOlICr{aBh)FX-A}%ujyzfuIE z%%0tu_h+8}&^ve;Sddp>uq&s}PIvELKZP!|UCcjV+Xd?=3t(GY#@zPx*UW8b*4JO7 zS;w10p=P{4lQ~Hq%A8H#nm#$rGt^sClVddIJd-*k51n**`nyEY%<|y!K}j;DB3eT& zEx1rjB7FiKIj7wD7mtXuYidk6In3ki0Zq-kI_=FAkGq<i8he2}p$QuNKm z0vyy9uq0SA#>dnp77>6_}WY+A`V_5BTEw-m)@pe%u#`!;R4v_&3Rm z;0f374FqO!;dYVSgddc}V$B2@>xgB0>1;Bn)#^+LNoBfVtfK@WqAT;*TO=xu_xHyo zN{iWSPd~iA^auWO6hH7sENgJP;x&Psc%ZCdYjJHUXuG!3+TyJZWr283peF8eH&nXa zmH4eZliYyclS>M1*_DM7Iex_;H|1qsGFatdxz%8_D~&?8(O~f^LUOyo#S?J7a#BQU ztP;7JplCu5bt3Z(c6mtQwHVA`Ze*K&;9G%M(Y;SwXDTl@)oDwbN997H)N<07#FbT5 zmCWHE_#uC<)9HVCnw`~WZl%`JuYnHj1AV3@rAO1Ogi!*jPWOgltfTQ21!LF2@^q09 zorg_O@IgB8Ion%_Cw>6@qSktflMaFySgk_m3?lOEWdGzYtJBz=995DZJd0XP`X<-H z)OJ9I=bwAU%D*P7rNnO!1?>idJt&ri{DI-K zo)c6%{ZRn~JTt#s$2<*PT2<8!9q(70hXekQjJVUHl*yImY=umwNY3lLbI;q>aFO+j z^Y1rK&9YWs&WtcuzIfB@LQ*5}dIdP{i}{3jpFS7tkOt63KnKAb4c8b5T*W0orGpzR zBO(dRk??IWoPul{vL;r#k+_)4K_gxS0BG6i8bHT_4cAeba!YbZ z+%O7Ipu#T9(m7o0>m&vFkx7YIB5f!wRL@zxdXBoVv_T3tCL{S}o`U|V(6i5mruqv! z%%K}@pdgH`{=;{eqnE2xbDubHjcoVu@NU^P2cDR#QeDm*edog$pZ)xjr{T+K;#x20j$W@J=a6$W z*GDaC7+!L<+Co#rxI(8>5aWoXvo}-6UOM&?wV5r;*VLPI7}^kmLqSSHV`OCFbmRqF zI55G1V1Sg^hz;cCaFGTZs?dhio6O@?-Op8DT-U19DE)f^{gcWR6Rj z#spTxV$OiT!yJy_mtn&XL&aK_A;8yg2`*;rg2spfrxd)CIxkM2XW5FhVX(Zdz*pI% z*>p~vV^X3zUI|I~A}jMtgOtmY#`Z!CiEI9%@u?RhlLK8{1I%x4{ms00UpJq-zHYxq zcHz8@msaOV_HXICfqV5?>ruC@@@?i0LU8cVwP;k8%N#v$+wD^0BR5`+oHX;*-u(|d z{K$`*brwpj(K0VHfA-3^EZcOz*}QxC@R<~UZfVW(+>u2~Ug4s*n3tao+B61fiPTtM zkY5_wetF`9o0qLS@3L^ES^Rcv=|D%vGU7F2;=HR2)w){G>XzEY!MIUWl8n|`8Vfg9 z_HT?=^qOO_trvDy-rC>2wlY}QGw@Kb@R81zE~_K2vGtLFA2pDkc?9!YuVZyEM%Qf@ z#{$a?#jV-S?A&$E9*fQlu*10j4Lw9(3F}E5!1Bt6&D`iAOQ+?6Q+5lw zn|T1-kWEad<&;PGRSP3V-&o2RF}(84vd(ANZ5g^79>6Ry@Y|WWIm^QQ9$s>P|5qyA zXL%bke%rE7Dn)Mi==b0Mwd}JbcUsmCT8Lj*22m}Z3FgE;2s1N4Vc=)*#Ld(T00tHg zACZsImjdVP$2^GjEv2zPtqwzl zs+Nt07myb&pQX|)yi;Tn$&~`Wd?M;H8b1r@m9JjAWbEL2*ND+%l}cB?jdkQdfD0`*Xu4NjTZ9+*i^UWJO4CrZhquykz zW_Gqfs3IFP4YJb?KB3H-%QG-Cg*HWM5`z1bfH{P{IAr;mB~)xj%j{*$Q?E=?1c zb~~NrM8!56^ASSK@gwh1A0LHLg%E3(U~c8^p&tX8jOX=U4(m%z!5TKt)w@n?y$jkX*%E00EfcAjbY1#mrmAw;oVMc`29tuQ%DiMs^ zDC7XS4;#ztNC(_tr}V%N*mHa&;T|3}g3oCIqLs7YHx@-Qd!3^Zwpt{M z#^Ci?Xr+a@xvlJPwrWevTxP5OTUi@Ne&ex~Pfvhip> zYJZ#%jWO5vlNWy~X}#bQ<~Z{Y$<)+)t&&e&mk=%99u@CCS#h!KiXQJ6552)xzh_y) zS2NcEp^eS_RrA+a-c$3pT0T%IwuV+4n<24_BbZiAg+58Xs=DqjUl$5M_?>(S?d<{GGw^vs= zFT3E_(xpwSUcKP5KQ9PY4{U31-*#1S!2rfRtiROLW{4jj0qj_nbsej}V2c#AH6XA! z!a^q_oPesZT*h$+Y8c3esVj90>v~v`XNi))bji{m_ti9A@wl!MX+h$!5e@+?BW%h|QQj$XV zlKj@3l37*)kvdyp0Ta*W&AE7^JeIF!hGzog98p0mYO9WJojJVASfM_Vi}i8HTOF24L~QA1%t zz0^6;(Yo}u(y}cC+Va52jzEr(Yu-i6WnSXp&<*Cd49r<}A^N+7m(5fP?FD9iz>=MN zbYo0(({-DgQR#K(ZYi8s#G%S$g*gg!jbN(jk}b*OTl@uYZc@&h5AejY?Gs{x-U;4i z7%_!;DjU2CCOd$Ibu0q_N!(+BHEK+zn3dwkK)n$qhd9v_55OfRZoh0qS$pTYi#LZY zN@6eZa+nhFbE!s`Hu5sPX5qSZcgDKTmB+t!n^lKO`u-xdBXiH4XwIsDQp#oQT#I=w z^Y-ZAhS*f~Qh{ndv#GrW`Bs=cGIZ7w=EW-;nNN#zKBx^`q@mMge}RtCH-Ja;N)`_> zN?^F-4N41$fbon)mDF!a2FNqmlSaI0{;vdE3xA7a0UUM*{u<8UEx6*Q0)5~N=fEOz zDhsS)0lwlLZewQ$Mr*cH2+$wjp<`<6BI6djBS=)`R)uOMe7#{wfuUU{o^Q2}Y5GbE zS`Mt!jq0?r;(_2A+nIdS9P5ZxFkEy&~RWT26u&kphM73mZ%Dz@f zbK$G|3vFKBBz5NEXsD;Ow11UCK=Ic|%*7=xXIwv_FH!2qgR5L2E;IkET`gpt&s!eN z*VE1`)~{Z*uzyHac@E0IMaDCnKW0^usK=_6OI23pdGL1=V$)@F#Tryf4(~C^I7XxW z9Q*xbf4!HG{rS*YeFgkEHx#TKn}4;A3O5KP=E{NdcPwMdxKb>nuzmMC@?aw? zPQG})S5dPnn_zCZu^tBH=$u`&fKLkrl6iBc>Q*iik|k>U(&~8~{c<#?)1=wWEaGYu z!fLLFFxxrKh6l&_0^x=Vv70V9p0$E2YK+NSSjGY6cve^x1w7|q&U2o-FpJUr;6Lw534Wrj{@ z7R*17UqCG)Kgsg4>z}Vm;cW_4p}ri9uqizSm>PSAn{MxpeV|tohIR>9AbLJSr)An|WRs7FD>o8q+(*$t@nH|*T1-- z#>3^>z7dotgMnGIHXk-4Ycw`sum13!TbkyScO0~PeJ=QF?ZMq|_-JHYr$XUH8><5I z7Z=LPWfzR(kW9T^as9S&h~?2QADQg2{U=-+n4< zcx#$!=nWQkL|WbwD>iU!H&m}Eo8P?ohH^)&EWg=L*tK5wN|}D`NO$)pt2WS1=Sq-} zUex5v(H_6OjZ)>5FSxqDd_pP~h!-(i!zDVA9Br%{Zy!BiP={=m*?V5s2jp>CVS~)0 z69)X@IkQXS?UF`4p#q+D^IlU-t5zKoK-7s%qxRWszA_p75%xK|?rxgn>z0Z=1^Eeq z@eGTlslVU9Okyv}$*Fhumls(0f(@jI`P=;?wsDO`{_?E*3H%yDe4L;OjK3C zq%Y=P+H%HumwPTi`=6<&3l-*ToOSuD7PZ;+CX?Q74~6VTBMj*Td^q0A`3KBZP!Ijr zy;)ah-I&revOph)4HFS~JunO~VW!(153pl#1M|Uf&8uR{K4N|c>lyjl8_{?G#H~A;>a#S=-gK?6mM8XnpN&Q=eO$$1I*|h z$Fp`^bvIGXldrvK_@cfmn6DmtbH26I)u2^=Tu=Hf7P~52^V^9VH{KnJwew;eo_B*- zr$-z3lKeim%Nh#!JkK3#Fzb||hOo_vH0U)wr4WZrGI3*xG*}fWkk-$6py6=wT%M_< zveXdoW?qHCF_GTQq|2Ty7bx;4cKOb^i0IhW=9t`){KQgTtS_(lcz5-$mX-2lJT+gX z>e2kI5dwo`CWXT2CHKcask*8;$``G@%r3{zpqY`-*@6T;n+Fo!ar2^az?8kQ-!aKSpnfLsCEa39=a7@pIl4GIK^M+{Ug z9Pu;!Qku3QNvPDUG7HJgSLZaTq%~^OEgHd7twq13)o-bFeY$9+WNro5gh1k1VvW2Q zsnNIvYOy%`?(C?T>X#N@6Gsa|^VK9*SY~oXbae%_#r6h^v7ggh$_p5ZDM^7_?+C7~ zFYF)nc#7x7Xd7S6p~dRg6kfG^iO;Cl8dVOJ%x;q^MRH=RTw2t6-?lPZqRVU1nv@pi z!`a%)CbhYrIaJQ7kdI%8%IxH;KnCR@5ta8lJL68F%S*fnE7M=lUPX6M6Nv z9CfZ&eRyu}kVWs8^yW7T%nkZ*c4xebZcufoV5-v>Wfrx}q9YZOB1gq`b7fuKn7=nS zU#L3AJ+Hmm;3L}9F2xtcIWChrSm4s;E5(2YtR46T^(55;z1C~NgLwsu1=ubCfU`oB z%eFj#BhC3)fUylP!#-LTasaXvH%@Eopckezz*Oh}aDxbb0?^5*)hR}eRcscL_$hRT zv+|qe2XKv91dTIKl|!Q?BTF1Tp=@_H%)?e5Dy)nSpxvSP!t3UQvz@`hzDxS&qP)NF zncU(Jhnr*O&e+@y(YZ)k>o8Q5mh~>03@^)X-rbh(o+#Tk5$@22Z|s^{+}-~fYPqJq zvfH4PRySCR9w%40Ym>LV`t!kPMU&@DvS(v^AU0z0DAmrU0n226d5)v`*i9?uED2TC zMrxXOgLd6i@#KPCF^f#0uz2ddYLi-JSiWcIz=iJz<6X-?lD)HFXI;i*KWYiYeQbo043}hGpLI({E<=QjBF%^~`&58-h+8;<$q)z$ z%SQGr)%+|_@Msns_KAUm;fTBHQdihyPXU&dsTop*G-y`w(uN^*R%yjjnx$h%9K#qq z0?@k*4r&Zw{1TSVFsVBSck@wMo2=@{!Xmvp2epPnXPJF+-OtLG&_g9kM|f$I*d}c( z^oOl4WOYQO4W?RO$AHLWHV{zk26VEgw628`OGtxL$PUM zTujF(vuMc*8aPXP0`M8s7Uxdl82<>7qLq|rW6Pa7g%EKlFnfc1K49fpc=E+_i*s$f zY@R@c2I=s0kAaX~1`T2A$w;hx>qe{}$TdD)jK-r6v|4ckbo=l ziDKv2xCU;?l!_Dd=EMv}O&_W;+Vpx7@pO*pxh5!aN59G|$c==~j#Q8Oo$EIlD}pN{ zPN=H1b)Cy)YlGTLsq?IP92j#F=#bg`_9EINq+#q@?rhPhNql_H@* z+z=0u0xlBq+VaZz&MWoG9KTA$RZ|jAi5J=)f`xPPWPF}ksCPFj#9~Wf2kFu2JDR}K z;?WStT*RxB*C?o)Nu^jMD{6uvJRzH3BqK;sZAdSY2&6npBo+pIwXLhi%X3Sme45m> z2Vk5qNl4}tXbl#+IpnfyKW!9N6W^q5* zTq&)L<-#*uRVT0&{COF~O>+TEJ!$$*qbE4{GMHM9MRppA;VrmGlP0D_?5Xi^Aw~fv zhy(Hl)($o`hjg=@)<8R8p}}uR1=_wEq;iTbNXRb)YyfV;XzJoH$q52`!ER*s{UAFo z0JJh+!;rT@DYOf1j*!UV6*vXC=R0AnQ)z|U!Y|Nz%Ih>rWoMqKKqNUQ#5Hkqmg_{h zA~iwGix@@QR&E_%wE2u(do}iIe!hh+5$e^~nt@FuQoVc(fiw=G$gCCjp!tuD)Iwq(ned&3P^+#ANm24lb! zQ%r9GLJfp8LJ1)R!ln^O*@R`25H`Ihn@u3S_iSDgz{7v;j6{IlytnWFp8ZLh8IA7T zbMLA5o}$ys#G=SFb+Rz#BXOC-Lg_zodvoG!3X>}e&|4;yAKISS?6p|Zc|yT&h{H#) zW`tZ6pZ;DT1Wj)Z{ZAKajTQ@|OXn`kmnK9@PpM`Kqt(Uh23z(%W;SJ9tQ2f`-0CM) z(P~p&_5i({lWM$6n;NZ(ap^d5t?}#eUh}1=z^Cv`LwbMp6cICJBizQ8g;{Wcu=lqt2DpNokhf=mUt^WR_6zASPztu?_m726P zjj|$66d70k*MO<2!Qw{_`TGSnTLFHd3i>siIUG&jv60 zRXCC0tNxbL6m_zjxtWNCA7ZF*BRiqNrMP9R6XJFMcgX?HQShoRW3)g*#P~?SEQS6- zfMMEJgycBZ4Dd0y*leM)5~~Dt8>6EViVl?I>Z?uKoPrypTH~`su^@}GMF{dM=ifr#LN6X4 zN!901U+_bR!khc)CKUOjA!f_-i~gi^Cd#=5_aFOYuVnShbXwFcw|uvM_o`*vqEO~r zV9xwfvQy=c-$K&STw*19H4N())NRx$@S)GfutJs$KvQPP0YpEOsR?5!hL&CV=gDIv zq*)pxVG$T-)zC9yJA%56{$i79Jk7L;{$g_f&eqHoojdy{XV*52RV*k8W(OY`Yp6wv z6~sE5Ed?paiXG$clox#(pO_f`X;C?0+HvFX2t*Ui*tN91yZ#RPe)=(bRDjl_Y@)ck zed(t0@A~`yTwGLJ)=$KQ_Ib%lSVK2POl0fZ0I9`Zc6GtT0-71?>JIq_;2#tZ0Ko)W z8#{?10t8DOYtRgYnAET)LZ-37xFpPS99ij<)WuST{>r&cI#2SXtQ_*Xwv1tJBu8l6 z=BmuLDqcv6;}cw^%~aq{BXiQ#3CVgfKQT$|%-Fz@Zlf=1G(3%ls>*RnGB2D5)uP0t zS)LS+e!g`VK|oZ^qN3y?5!vWccsdMJq*!TB$(O{_u@CO2bNI!!^aNWq{Dx9S_FgQ~ zXvi)N% z;BN{(GBVfj+adghvQpDiz5T13M;jZLTzBJ8X(6Jxx@e&;<*%nE>N%)5A@0^)=Iki5 zFflKE(f)Nw>cmu9fg75_G|9BFBmw@$m*T5LECDw~=I#-Ed5HrQJFlPpbz z<*kiN-g)UhdVroHMsZ8#$pi^T0o83D0EB<3r8BC#z>6epPxEL%ef zYZ8@G2{8g~9)Z`N;YH^|9|(k>vIdUO33xvJ1Dx8R19T6*RE96*z|n)yA36Tb4RBHe zuiDTHY7or2^cZ)5n$6S@Q9|}LD|kOU@X6$q9_b&^3 zuL1VxJv_)xbYL>(_q%Pv8I1{o&tn2O`G{Vzt`X@q)-4 z&R9;)`PIY|gvkScXYkuFexsko?}PZQ3%}8`@cWd@Z|phx5?`R_;dkcV(B*$Jm;3R1 z=$6&^nECkvd_)CeV=p|VR#VxrvHt7}PmwR-tMKL zD?$`VQ;@Qd9*R-M;8$|af}6INnKZJvcjyd@IU`l0y+y(WAD8Z~n^I7;Ix$-MZT4D0 zmy|0kE}0cQ1+0b~{av~|^pCR=OZw6^w*_pr0DhsOp@9^$3C;ghDpe=M=2>m$Q29!2 zN5`hIl$a&^=nHjpvE+jE)I^l9-B_X1c~QmBN7{cCYkq+G7eRhw%K}?op3R=054;)g z@4icX558D>z~BlNX3PRHD6lUB{s9c!MqijSO4;2@<|;PFK_)Q{j1c*QZ)Mph7F2#8 z@qM8-T5nQ5e7`gP^L=`&7p+uFrf3rWmYtNAma9l?8C-eWp^^r3AoI*^Ggir!@%x_X zJoS3;NOfXfyhNu_f~!Q=4TS54@&z{#5@Zy{F6^w^JA)S1xu&dJcVyu9`f0PM9lxxk z6)TT@E|Mqi+>*5%eYxuVCT?>7WakazFW<0)J`;Tr=X0YM5S)lhIL9)~Db|mmr`YM0 z;Be?e0*RJF%>s$;1D;^~xL70L5fdaZHt1436#JoIjTG`KbMTn3IDn{?eX}exPCl?$ zQ#dep3CA~k{W7=%o&#wT$qcfL$;$@bz_5eqm$Pf0MnB*TnIS5s+n29*e0ZX_xO#lt z@y5mzXl06%{=51w_1?^`uS-t3x|iX0F1^kvB*s{;SXQlP;>0l$`ur}Y@?aczokN1p zG$-r48zW;M1TxJJ>l>WH4Wmz%mDI*0414aKy=Zg$E^08KexsyG$J-f~m{h$z%RM5` zqHY>oiLxH;sF5qp22bncBV7+l)q4I&<_!AP_7YSX5E|p%YT8}bP`vY-B(6xWmK|W= zy!1MMh}42U!{oFCNs7%ta2y6b1urtPBm!g->&2v^GxCQXeC4NCzxwWmr~*eCeVbA( zZCV8<*#J zeuQC$d8xRh0ayNJCgVCIusLQ!Y-sfdbV9#^ohjT6Vz;y7>u2b333_9bG1)n}-Kpk2 zCTp8Cw!Wd7;Pec>vSTdUd>d+SE1Ow8FiDfc)uri8iz-T|b~E#EhR7wSV7x&b2q@&> zsy0r9{7^vS)aU$9kmo46@OosS+_z9jz>U&BW@(za~ zg8gi~6be%n$E<2&70&F9 z>8+$5<^ghf8f6TH;MvDJMBq4z^;v);yky5>1*xY!WtmDBfA^A8T@4+lqAaQk>2e~G zh>eet_s#DstVue$Um3%bCQoQs-8nT!--vpCaFz1R(Rz;b(02!r)8fK7K;p3_#pEo= zeyYKq?9A?jju}G=zq2UFGea&iyjlWQt&SaeQrysbhTh*&GeCbg(6a9KhE}8Mc_L@| zs!LXzh<+q7sqGOo@LbQpkG;h?d~|Yo5d<3V9I`~ChCdzOXe#)q%f#lVhUXLc06SEX z!g7M)mse3Ebb-j{`u1*j7U;RVqY{&NqQ9nSei92~m(5*5tj!V_ly3F-%qZAI4dDuB z2DJlXX;@fbj~u6l!1_PKht262q&OMzM}!YS?X0z2U_uBPD;gjb7739|gKE4$*x^T}{yq zGPML8fdH53tyB=;O$2y(W(+SLZ8po05(3cJsgBW8!KX&!Cry8he&HF3d(%IX62-T2 z^~n6}l;{_h-162jk3MeoljuvLM(tJ_g_$%&bXrfdj=q~7y#DCS1^)p%^eEeWZa$@o%bOINzj!;*+H?3nVU7&V zlWWOEc$^USOU8_mOaL?O3 zV;Dl4=Lp+v!%JC3K?1iR(8)|5OP8M$rU&Zfd6r8Z*T&rf|`QoUe*Z!I-Y zh*awn^X}LTRjN9sZYZd}6T26Np1F_Q1Ng4Pkiq`^WtNo=stzzQy!->o0hm{?-nWmw z^x*x=R*v=DFu8qnt$MKX6tXT8a z{ypE)`!CZ%AvFpbb%+*#3Rq&mK*IhKyci*f=?;MW--yDMbMJ3KQD4nyw(F7~9(?7C z=G|`X|0oyl+p;`clj-(Yy2P(krif#dj>T2S|2r88b41rtPI5WO$W#^zJQ-MXgq1Tq zU$BYE(l+ab1RP5T7C$2&e3bLZ?R$=7cS*D9(UrOc4tl0wF24ZP+@rEhs-A?(|I$<3 zS$vW>sfdsEW zD-g8I1SCV*3W!L-vfkt8ocB~rYVCe?_ifKlZ*W_`dG7Ts?alg``O`AxY$*!$ytCP#405Z^@11Ag=qy>f@$l zy&37T9OYpQ#H-nQsD6SaDeQBS8zG=Rp-(x!m`~KvrwU?t&&Jx7y$M7=fBat5mm%Rk zC-chWDyg3MB|}LX^%8G?Owzb8B>|45ES^&}OQ0UldUulZog%G-u+0no4v zqie~Z7##6IJU{qW!V@q)vnm3!;RdZ2`4`;>~o!2=W$w;v;{ePn1_T zG|o7F*Vv2{ea`9)ztKPRyVjjw+|{AoHtD*_!}oc8liUN6Ki60j+uU~go{AmIx`{#h zoyex9r4@5#50t3}Htbx~zbJEYeN#nBa@|l#^{VDzL4#YpAh(lKnq#e*Tw;f;)(k%Y zc@PQmz>KS>fJ7h|7R|~7=&{jkgq0~qC}@#i!NI-d$c$zV6?wX;n0^Y2hqSGuK`W28 zQ|Jv!pD4b8n}Ue1RP;qI7YXTViasyr>gg^lGvsUka_h8R$COWkodj}&8{9aQx$sA& z%QHoC?A$`=56gG6L4IPs%VD%(>`?}qehib9KddGj$!z-0{%wUiQ^mZlQy$$69 zA=O(kXS0X&ye$ayRj-;YbTTw&T>8H;~q zz3Gt8#P8heKa*ahGmKZ~!v}O^_=t@DPgQ$PXBYzygbqU3>c9BS|5E8^$9E1l!Z z(wtIyar%Xx74-ql5-egTuR<@y-?}j6Qbc)fZn`>En>Qg}L!0uoZa!Cu=hsJ#k|g(o zkZr}-8*I|pkYY*7OhtiGJzbxexa5M=m{z1US-G33yXhw^Kk?jliL$w{Qwhkyw$%e| zJ;$`gFtE!Klrir~Qm?q&hRjr)S*qup3nYu#CN$LDDBt=M+s;Ai9QO!QKNlQWFlWRq zG1Q6~daRr}7ohh(v~keUQ|!_d=TG0d`vw&KP9ul#*igkJ!{SK|TF-<9mGv~;hhdEH za;rH8SXYWb1k)$Hnve_@9=BSSlu}V|y=dt$Sca+V4%c!F^wXWAuU&j}qF6#r#B!6s zzvqoW%yKkS>F(+ljGzgd!_DzVu4%50KCD=rS$gsHdUIwEd2ai_HO;ruv+6ItQ7_lA zk7E1Eu|Z$KQZ{0*J$8c$M1TUxIkpSu=1L$jMukgbb!f@ViC%L1l$g3av)iI9nxMJ( z7ObwY{pEhmv;pSQzqWF1v)r#PygyG2&6c~FW;1H&oD1iss__+<+HTjAt`>MupSV8H zMlU|=b z+(obJy5LJ{el}y)7DBzH)f|r&r^UpTDV*L?7yDT39YD}l_y z9Dr$;6`W!8FoeaW5qP9vwX}y`e{khr@3`Z5-`}>(eV~#jfwb^0RQl+<_uu!Id3U2? zkw8VfC|0ih^YkfGrf0i1WZ5Nw;jgDn?w$5Fc!e;y7;z{60_9_BS#j|^Gg<~lMZic# zRlCfaJ*>AKm_>+x;UdjxKXEsG*QTm!Z^i;+#&GAn(Jx20=5=n6A}a7`@jKM}RK$Av z$JDl#JA)QS#mEVPGi!3=QeR2&P`rV(D1S7%32;DS=d**D2qP?mD3r^Z8z2VbF@fn6 z5}V)=NKXT?23-RS$+u?S2DRGwNqVZ)SKX}KG54-%$WylCR`S5ANfn~#_=LKAeX%}G ztLh%#u&W9(Urx!4>(>DL#q!g4sg!t~%Y)~c82Ncw6aK>|;!cG7fO%F}3B%Wk*0u9D zs#S(hGF(>w?|n(L_;&Za^x&H%^ADxX_f|{2)uok>ahm_7d)M!(4u-ntikFQG|F&Y5 zO6kZ=%&*XL_@+;|QKl=QkT}$Dz2Yt@;JK{6W-^r)LnsKrVcDh(@h4EF-cmOfz0o)`s zl^!;@hx2!%)qZ>Sajq@V+^mz6^vmX(oL+mn&p(1NwrG)lqeAvKmdQx2z8F!7?SB%N%SjY0Irnu)Va<;UUgk| zpp(w+EXZkX&&}?kbGmZ_ReeEsJwXH})#PQjwjU_y?#a!YF_Zowx4kM5oQx3`^Y=ed z^C>%1aZQ5Ep_#%O9=7eN`4?@|NZtcdv8lJDa8BC-au$7&E+|18?`}b*3TvF$XkDC6_X$ z{hD+9Ow7|LL6H0zXbsx}5qcfVopHw%_)HKqe@0IMTyxRQrELq31mmNJ&?jgO`i-!W zg^l;or%|D=dA>P6ir+!E6A*<6;~#M&l}agrdL0o^zX3t~D~o6t4X{!R8U@3=aNH1n z5-1o@-V5V5#C_rzBG|f1^_WBdkDbMEU=HMC`^It8s=37-%GSSlPkB=Mx`ujdw->AZsig%= z%EnvjDrUD9R88%e{K~@m_3c)(YlUo5<lC!L?p~dLOnU%#4&zO*Z+BANTN+wZ| z5hiOcoo!4qCTRT~3@%S6PE*5SPJdbRxy(}Wgh}zV!CnBo6Q@^hQb6Shz0xhnQZ{6{ zbvcVtVk6VDvTkmc=Cqcs=|3qDbS?M)Bxf!*@+^m^B>A8JO+%fPjR7mQ8 z=SDJ83)@g3-4Ptj;RGljkVQ`F2D8$v=5F{soqM^Z3)wS0P9HQyKYB%*n2-NR{z`lZ zUUV{6r^6}+G;^gX#vC)t1>~=@<`lbz>6v(B*%RdvXQ46bu*x@|R&3%vKY0g%w{Rt%t0V zrQViWS(aXq2%&cNs;arV!r{uyy!bRZ(Kavd@TF-t&xnnTN=ykR^re*56jr_`+_q-s zM+cimRuNCc%uUU!Y=}+da)halMoX2fE7u#BY9_ApCPqqA@*d^K4mNEV3KrXv=^t-Q zHC35i&MpRqYHBvM5n#{(3??(w)c~oBIVyx6Vxna@ER?jDn?*=Y&3^wm(aNaFJ9WWA z|5)DfK1pEKp)SR7luIt9CG*ftx+r=d>Zcs;%$kBm>R4w}Tsr}2UdE?$<%EP5@I&MF z1XV|V0`d+&lhH~qTSxeDtUUr|3B%s0y1VInGsd*a7}v(pAJRsW4EpEk2=7dj&Kgfh zY%TU=BYESW=sODLD)bU^`;uR?r^uD#Uu8|#xCn!zJ_#Plz)5naP|Xo8h*E+|Upyd3 zKr74~v99Mt3ML~ni*-2^BxdH!a2)3F3ORR*sibOw_d$z;Q0k(F zb*(Gti_gV!WBh>})QX5y?0W= zhdGLc6Lq9;QRiqcAsM9}93)aw)BEWMiD;obL1H1=drNbi^d{oFjz4>bU3H=~o>+H! zY_YxDjN!uaw}m@MHsYGh7z0`S(m|3QKTZY%U~mWfGGdZHeR4$`eE{-pLdWht_et%t zThJYDp8nl37d?H9BG95y+muCYdo!TDL6E$d&oOITAx4TbIN-s8A%H=VgK^L3VvIYC z!hpDg1bvWhV%lDqB;qF{?w{4mMZN>-RF_mLxvOle9I6oqiElXsy%s+W^Ag=p0dtCX zTl|aFDN%$n_pBCOmu9hMA#4X?*lI{2+09@H=$a&+9ULADKmr}Jq96D>b3_W$Iu1)b z3b9zRrqE8tS(Gx3IO}0ao^hg0rYs`$!qTNQo#u4rEr^Rok!p3BNZ`ET#8}SSc+8@J z&p*k1o_vL|lR)RhlJc^J#5@3CW<(|XIM!%F+~+@C{@x>_D_%vD_YPz@wOV0Hn_Fuw za%L3BOzjqxXx6L5+vM}~_>#X*FaF|-_NtlY)6a?=is%(bjvSk_R-%zu^N$iI@bfP{ zL)B5QF?t0Uh8Qtp!QDONkAxK;X568g1TX9*8R8l+$pq=A>gXTKa$Sz{(>&EHiw1{% zhD&E&U2f!PAD|zcUZF9#t7`o#cRqA|m#$@XrE&E(ajko`&8TP7Od{Jc9WIDq%VpI^!|5x56h^eT8r2pH02)rl$f8iS?ze z#l1Cu$sA6b(KDx~aahEe#VIeSnOhs3MKhzU6{{G`6x{1l7V zX3SK@N#-Y3V%R9am+$yaP8#IMvVqql&af8Zqbzm6m?yKVZ-Bh8?1oG@DYFlAFR7fv zaEWy0jOAv(tBRN(GOUq-AE0&KOg~@Wu+pg<^z~W$GEb6D)1-(i-ihjiS#OAVqJtfb^*JX?;Epg*_9$bG{W$X0`ttJQyNKPpUWZlnk+(tjw z&@h&rkfYJIufOlc{Bny%Z8-m!^_9H-c7;8Te$-l{Ue-A=w=>Gb%b46BW7eUTn_4T> z2^v>qO29y57}Aq*>L!M6U*(@9U&MPtO#MbYtMD=~%QnpH0+^ujvV0zpmcdVkoFL}( zN{R+7;Ga}Frza$=dVqKQwE?<+ppm|>abaKJ^<%j`Xj#uK3-`5E^zN+5E!w)acP@Hd z8ZahAixqB-jBnL^EZw^D__{Ku+bR_%$aB4gtJ}P`pip1Bw##FrPwB>V{RNN_T_K!a z3;o8n+N;8IoP6*L>-d+R1M~SKAq-B^JRdAU{ihHi5Zc0XS3_0*+7~NW5uP!YdxZ$6 zlSb~A%P){ruY)uj*v21-N*C=}1AQ*knWJbi)wh_1S$vwm<?^Sr2DUD2ev5P-+&wYdpWD;5a@&k$X$iiZiM;_Yx$Y0m;h)Gk1v2o4?&p`PByo9n zA@TXQSo8Q>PV)fyi?7nBD)(hVMZNY$Pu7Gi&*LsgzHOwXHQD)d>e8|s%LiBkIyU86 z16swow=gHSFtQ{kSE0Un1e?>=s7JA_dg(>}SvS^+EbjF zBPU9aU%aH%+v96vqL&Z2F0P*)H4A~)Wq<#cQg@r!@S-*ef2W{-rk^`8D42u#2$!wR zHQj)o+*`Yu{yaLUYpv7wWC#=D;vMy#Kc9=z+_?NjblPEc7~0ECXEx76*6&-}7OG`= zw>xYO(bEu&`vGVr)40+5DLc_B1{xf0fifezq5 ze8!89&5U=Y(C^V_c4a{Z)t`%t>kB82e=~jht_g)pxv@Rl-+u3kV@~}Y36y|OpQWE| zQ4-RM@@9A7V#3Jm+rTx7i<;NGz`f#_;iogG_o!NC4}>5&P)C^&6S0ty73^Cd_1@Nd z$DI|GQhidshqDkxKADv@S!Jhc>G^c|0W|c2TIA%=JtgiF$B{J_yLmHhHu3VQgUo&i zK~j(-4ab~Dgj8vxFV@G)pLv#kou0OM{MVxN`|d|JMVUpMtPP@9C+>4o2kB48p9^-P z*T&D76OSE3j?#powiCmjpufdJ`@9Gr-6lNAy%{{pvCmHm@YWiLm%>~GMh)a1YdeAr zFt9iSOY68qDJ+HKVKobgD^LDd6ml3mV`a+KLQ;5=9v}aCO9iA`Q)x?5gMUZDLBJ>? zYhHYsHc@ZFK% z^ez3Y0+rFm#XslIv-5~PdjFL|)SsMg&}_f*3M*FeI?~hpY^Vz?gjF28|IFYY3>69m zd;hy3_~XIhXD|Jw?8abe(hTB>jEk=S3`Fw9xo;ONc8EAczlhde*~vfZHeRcte}HP1 zw*m%aLe|-8h=&Hgf+rc+CrmWcZQw6{X5zu~1~Up)tp)-E@gF8T=EgA9rOR^RK3FUx zL5IMbmlYCWTs1Wz!nri-_k{>afqu9kj*{{GRLNLz*}O%fHow!7~_$)tNc z!_@=wsZ;;)QE%^9dtimUwYKh0+>OV~HCZ+E;e(^ZYwz+keVawy2|!KZlB23Pr#6lhXa{jJ2nJr(pu zr5<^@H?+$b{_-;KEQ~{DL|#NOGX`Whssup895#X%+SFo*JEZzHQA8XNefv$i5@ z)%@7WuWH>q`fL5*a9KrhK|H-4O>NlLD`)x0rP-WcIbTC=I>zr7NEa)qSG}%UT;VX# zVZ)6<0XSpKDLjYFF+=_TdL{?U^w;Qxy)~;^X7&sZ_l>smHf}sPH|MxsUcdR!L#So? zwxBmypZ2K0JF#rev2=5Vb+~>w#~*M9J-*(u;p)s%N0P53t75e<%c^$=7u0oRbuXJ< zSi7vhvJKMlBw1P&j@+T;tF?xVGM9#o<-4+z8b+hjYy8IicE2S#KC7U_ku!z#X)r;GJ)WX)*C@rRY1)FUlb_tNigm3cDnEPA@(j@L7n(0_e6 zdqP`VLql7OddBv{vsNwDMwhw!;#SUWjPgd!ub_X~wPw?iyLUGR$WNYFIeXf@^o!of zEkShs^G(y%XD&H%0(n(QZgaZJ70mLd$GDn|)yDWTT@=Lp#@kaY{wz*f&!#n<4GU)O z8^*F7>v3I#hq@TT%l|X1Botw!FlR#qH-k1IED2xW{0koa@8>(x9L9`9%wq670gsu& z6ZIbKd^)?)}QN+T*mi z1N~O9ZGU6&rnIRBgJC357?;a5gU1iEL?9KMZYaC}1*bq}aK@~s z;X&d+;(XU9Olx0&yiD>se}-8+byGaOQgvRFASJ%LXvlU%%25mBAUc4Ov*se1@f zbZlj8+o~2$(L#Mr(AHWBHP457`+TPIm`4`>7|5#fD-B87lP3co29B>h`pM}xTg#^w z2eLb?k=GB5pFCtKMPO!%BF{s4Ri8k9rrz+3u6?8N;bx^wzNk+%7=;%m} znq9wBZJcp8K?pWXzu2-hQ=cg>PKb@wwJcws;E#TI-q%4W3M&+8KSkxpYRIg*{h90L zB^W07jk3J$CMdaNY4$aq{5iPP7W+Nz-aO|sU(QVw`cL_pWohKo7P!WJ%577lhyS> z(3&h(xau{rv58eVN?EL?^d>SLN)=K^_)Xri1W&r$x31hy|MlZ-w*DN)s#b#??Htmz z)+}nMu5PHWuC6DytjB9Zmu}+Mb8=x_Z#Byk7`bhN2@Nk^!SV0A;GhCAW^r;D1MrM9 zFJmkbvT*=Jpa=FHZi4_W7Apvb7#Q{e1Chqk1|yR|+&~ry3_o^2d2}cJ5z*PBHPsg6 z5M_-#i`7ZwJCr6z*ZTP-dEBjz!`E;9Vp2x1E2C)o-Q|0b`M{6#SDV__Y^hC~G}>I8 zFP+w!lkOH#QCV~21X-$ttil+bJ3(iSo>rlY<8rw=zrtiswyr`=C1?>R?GSy}o`5lL zYi^Wk(TXI!8!sO2jnnoP7OknPT<9)YUSD*Vsy6e^BOi>ghJDEI;PqEl<{8H=x9>p|1R{n;$D6<$3Uol9-J3B#KJR{0~`-9%}{k8ce#OqBjtTejP zOoV;%Gl_9-rOMDS(G(Y5=z-ckQL$;|-c;$tG)S0JB+(GbB5h~U*#5m<-$Zfb*G(_v zN;T-q=6m9!lk7>$lFA!g1FFi>vdX%$>hx5HXVyvEB*>TMyYz@)kP3jtH3Vz83nG>R zpWOiYWpBhB0Q(x@PJ`=Na#CzEeuI>ptVm@Lgk_ur8T)`ZN9GPIPjHeI`x;Jtox0~Fz zcinQkU{lwvy9M;~rca;vV6dVyC!;Pi)#sDDU4$kz&y{=P`UmK5kI>J5S>iC)3HImZ zj5*Tcgg4*ThQ_#&^s_2AN=?5v88@++Y0N~wo>pc(fOz-uIrnlD2hvL4UCxbM&iy#8 z)Vlj#5qTd!;Q&f2yGUddOdTfv?zVdk9{NcX#IKU_=NI+ayxkL>c8%T_XX|lje2H`O6sU8B9|DER4Nhh~CZXvZnjWWv~Iv{?s_KE3(Ixs-0&TLFKkI%SO1+n4@#A z6Ddbfvn*=2oze5M1>H<8WtbO6fEf)&ypI)TvW#8>_=aae?=>>`BGUqx$Jz34R2U^Evmt0ISM%dkf_UcC;dhz_> z8rO9@+%jS1`a@J5k}j&h`C;N|IYAn}kM7b+#Mp?`oOYX1ahnm}@eYzBkZ}OUD#YAa zpM~GmLS~#eA$-LEghAjPTzcKyh4+6<)9aE;E6PWRvv*s9iZRYR=z;#3yM~rTS=*D7 z(|hmQG)kmY>`gIwGR{EWNo$dg;#eqgBvp_h6~EITUsk`hMB4+2^!c&c%DfP)5uXVb zLflL$=D`f##cRKi>PN5pJ1i7vD&!Ce^DYE>5&9zZGfrFA8FJq7sz)9%L>4&`X$QZqUv zRkxnhT6~d>oPl4EhIs#aE!W zEC&nsH_Ge|cHCnx>Mplrc$4UHaMGOkjX#Ed5u9n;pRy3%oagVA8l5uZOQ;Gp=w{|z zKe}RvrLWv$4?xn29+WTQ2_maKRTfP_U^5DMhBIrjC#UDyk~hAe7Wf4zGrdqS$q*$G z3Zo?|_uxrsnI$v7+a!sztv$*Wm08L?YD@EU2EQUci>x5uWi*;=#vH@P!7l%J4&XZs zD7;vnhFMt%s6PTSvcetgyvLh0c>-+hVIVKib>9JyuhKt1n{OalwvriRC*vqK?qJhz*%k96tZv@6$g7#OBguQPPyop8aozel+23SOnAbZNVaS1VQ4_-F1t@TsYWC^snN%JO2DN#smL2`V(OB^si7SRB4YC6nFZ zSbjXDpjoqvW$fs(SPRxYmE1F7W_wU1Giq&RpWk}2x>;&D`O$CJ7q+2?dYy)7K948n z^K7LptLuC*P{2g2P7k!%$MADtPU#|wFN!m2ttFq{aN5%CwSRvJ1%~Y{ zxQ{TjVm{xB`DAj3!c3WPMxO1*m0sZGj3;33zwly_g8KqR0Ht!6uV>JFT@hj{i zLOcmZI-prL?*^uMhNyv_e|Hj+6TjLaC$MCDnZM|7uN4|n4yP229@h-c5-Ex_(x|vg z5rKeK(XEk*wMo8LOzmQcfbpY&F&dx4T^unZA{~zrtNvcmKFmhwfeg!JgiL7h0;37j zD`sm2dIb@=+{J?vI@fJ1nISEe4(6BeH{5j3#^;0H+=Beb-Lu!^{FpNmrwWSfBK6Vp z{}rorF3C0An>PMKiC$rsOA|?hrLM)Qvj&%EB_+yal4Q@A992dFoQ^jLt0loXwqo>Go*(Mk!Bj zKANoMa}d8NV}HY1d4IH2kv{(?l(8Q<%2fiVOsb1*qIvWkQ_>_PrtOG3c`}dT7E^j}A^Ak&x(w6m5-LK0`l|nd6rQY2+I?CX%HVmT~f+ei5GI zFgv+y6Zt^jOOtVpS?ii6b(W0{(=`44-{~Le^A8K;QQMAi|7-m0ccWh(4dy)NtWuJP z61l|cwzkRH1Ie}REvurX>WLlX=&{y+9^(-Zfx*m~TX2RPW1i1gW8ljhwoKVD8t6h2 zNPDnPn19$1KSQQetrLr5J)^r5Nf`r>BpD@vJGs5Yt7wvc^_{Mi>0 zRoVo7e3Vcaxla&C<8qv~Jh44W$nqqVEf^y6q5f+Kc8tr6eFQTMl?kz~iwD4Oz_cb9 z+PUzeA*&)Oi~jlMSG>=A={M>4e86o4<0rQ_z$X8!`k1zw%O9{W@BAhC3@+e zx%-hci-Yb=7ZAe=E4e)_tt=&3lb9K-aWBg-ZAhuzJr9Sq01fOB9w#H%xIN4{lG#dB zm`)ij)|4gTsBBUT!gb{D1YHV-;3*R`=y$GhyL~CYLxih%!-NKZ%aXWd+8~$DkgX7 zR!h~wuNQP*-_o_R+UK-%eYm8}uT!-SJiQ+Mxz3vIwAxH|jU~z8$j_UlH!ru4QCyNE zrlhXjD{1f4<@sqUV_r;!)TqT_)-YZ+p^{wuJN{o80*gawq2~rYOn+$I1+EB{(zdhT zUfllq*(3Kost_cYUx-XDUy9-(rCT8~KKkf~yL)p59$S#IYtb&wfa-j&y>bH-i%(oWK<@G=?x*a17BQ;VyWt>;e$sx|@p!8XD<= zr$+a#TbEg|c*(rR{if6LiyII9B!ze?-+5G9S2y3P7Dfvt{hnwAkus`NtJkDEQYFf+ zfN$5+KzKc+nB zc2AqxJAwPnvzwO`_djb7T2o3C5&=De$2MXLe-D*`;Q&6y@=~B`)?L{MdB0gKWZwCE z=r1qQkG9H`3Y~ZA5?Zw6*_(;y$^^&y_W0ydWl`#9dvBk@t)G6%wq;#rv#j1o$%w?1 zh3?HycH|6{Lbe;`c@K%skl#ZcU4Vxn0(fTVd9hS7OL`s!_(HPA872r=bY;*A4n$`L zbHx)D(8Jlg=gpue&lq`{{_RI_YJRFQKXEOZf5)RJJ!^i6v~c6jJ!jFx&dysSZKdwz zs5IE9a@;4+SXwp_)n+xvEA6rjr$8<#ANkUEyUR6kYp8E`@(mzc^tf+~9mUKf^a^hr zFv1a3f5w&v=405ITDo=4qvP)5<2k!VC!KTujnw?D**dd0AI*Oy=*XX&o2WLJ>wqE>r_NU8#ABG0GJ_dR;a=yL+_X~FmB=uGBLL>3()MBc&P$(LOCO8 z!g2>Jzsvdsj1m|uudiQnL!LXp&#p&ihqo&;hlm!L6Cu}q8J9{=5Jw(gzisByRh`-E zfXxw6jsBaa<(1EGZ&&2zaG}nVjZ#Qb;y48IxbN;8L>D&qwI^r;cBJafo1ly?^Xb*n z(gH(8Y_!-hucN$SW5?orCyyr~Ww+dk4m~fAa4q zw=;2MVA0`y7Y47wP~f@+mydBOvHR%`deOy$G(W$*taaDqWe5A5DMnRyRgc+V^EnOv z%+7ukM2%?H7%|7*d_!ql!99M9P4kOf;;U}=nA$h>2qrS?##m=K3cNmx-K!64uz*~l z;bn}TEA(odkuyXM;au;Ks(ANfhURFoKyoqrzgI?BJVF8CddSzp#8QF|!f+l&E(3bth;R%U zbB?|I81{(!&tw_{h~&ccmm=<Xih`aA#PZGCkBK(csx9@$bJeOl7gz&I9#P35J%`_-~ zrW4Tq&vRutSxQtS(Nkq{+PyigAAds*Jw70bkJCH2vcsEEsxLVq z!K%$%eq%LHASmCTQLseU8z-n_@HSEeLC);nG=n>^ya#L|%&hRZ>JSH*#lNa4VHhw- zBvx8P2UNz5CXR6Yvkgn=8FW54vkdJ|3UBtQ42 zK~)!2AW8BS-i2=OZXF_;BsQrDk9_E|6xzl-%>)7YVWL80D#4-2o$*n{7xa7 z2E)|TJqeYv;xIN$tYj>CvNd#83_a!Sdb+WjHY ztr6IzZggB6n;1!-Y_BX`FgpKeY^+&jiRDwA*dO-n+3ugwieaShWAp*WuM+^dW-_nT z4Pe$7j&YT4fUkx0AUvyhPDB3;u%a{5ati2a?~e4nzYkFKqffM%rp689pKlmBO}~5W zJpFWIzHTL|8<~$1vgQ}Z7H%9v!IwaJy1l8(fan8nHrb1#5~7s*9=lSNc>KOip$Wb3 z7P&5ZX;~GjXO)UHJF8Tr2uJlnc2X5aeiX^IG&5QTrooh}-~~}nT)|4h_y|m#QNjLL zCA!QV8O{PQhu|H|HGH*g`;FV^*>nyB?|mhe#de~~od@Tg-Zyi#-}<}KG@pKwQJNO) zyFzK|-{h719ZFOv(Wh7MsFBVWnKZp59Qt*s|O<%vY zhkks+kG&Vhwe1!vujG7uM;dn<@#Iu=kl05X)aZH+eKzT0wAGBX4=AlBA}#BkNH+E+ zRVblWf`4pr=m~)Htc}GGc<5oUJC4&Cf!tx1`~5&Hc>Lg>Q8!%(9B*J99oU9KE|k!3 zKTL0oad|(^oUtbOL|kOX_>gL*gLu=J@GO1Xc;(*KY#I6psej5v(M4%NDm5MXVgvT% zU*p~hxVUX9Z)FKdRE~eBMz8bAH%^nqCrSyPO!P=3#6BtJ6epdVDvL4hFa-1>brNZL zT!=^ly+L1$|7)QPDzajIDPG8<+zh|QV|EQhjC_Y~bD+QfR`f7N84H`&CFEgfwn`lS z_c1glWg^e`zC?iLZL9Wzi#4I^OD~(y)QuAs6{Y18t_bJYTa}rOEo|fZl)9|~00=69zaiq_xyNfZ9nvo-3se!j1Lg+D)dSInyUh5! zU=C&ut!VgIr!UOgq2M&|c19n@E8kbb4{RRHV)z}_ae(86bvLHo599!4Ss%L^NO^Uj z%Q04VNaF-z@tfipuZ|Fp#4}DAA&)QQ?2}8spkJ~0OW)1k{`251Dr02zqR1BEP^ndL z^V-gWgv1r}*5hB4(nlo$adfLv#B`EE;OQGZqRb@JAjVujHi>ZVp^<=)J zKGLkx7{zi8PgN-tse|gIQHub|oFv7_Y`G?r%vF(@1cm1;CQD-VJJIFCPcF~4i%h$> z|CJ|L#!;s|!h2viK31ApQ;)XKx@BS}or%w!PJZPC&xLR&Ip2(J&97>5=3m)SvU5^R zQ0of!(qjns(&DV}B)6BodUZbqCKyjVnt6CUp`Yv;n*YD)E&htJ`#>YUIxmXAtMs&TIF2Qkb7!G>x z52inaajL;+%}YUH+~T1Fp79f{eco>=>Gz!0spo%d?)QGpxbNRw0!>)253R$=R?i%DjpALR?r6sM=gN;u<^2aCCjx`l|agu}tl{r@&6~qwimgUQa}4nYX+WRYmeVo!!mq14X5=-EOzt5vmeaqXtlYk7MD;-Dt!u`f zxK1naG^>JwlmtZ-s)|aAS4!?5wCp&sB2~YsDKTEF&hq308|NpMjfa+q|Er2+lvEXAX4S?_q(~Cmy z;cn86??DfhIIL9qOM9o-%}LS329Z3usn4Y06FoZ4e#cY!S!HBQw9Sy(XUg(gFb?28 z|3Z0SKN-TTSt%TvN~|%nyb$`2xi{sZ-`Kpi_O7QB#njZrZ5vv$9B!$vt+bkR>~X8I zaf(%9%CENP8_bz8`7r@+2A1(?2dN=z!4oSET89y4wWyHHX2yinG_0&_HlxOkW$TiOJM(_b(+WQyp2H1LJhnwr3 zbMWO4Pd}GuD7)HS;o{A29liYyqm=wDdCIn#3zF#%GMoOnCVB!djHAdEo5o+*S?AncI>rDX)dYAJ1@6iO-O6?m_YQc6o7 zl$OLdzwewY+42Y^egE-uBI)Yt+;5-neCM3+oa3MPFJ{m5z$f)DIxY8A6_%Se8G|kpm6#V|F_ehdoR69Eiz4Sc9a(y zcz-G=3{%Yq`wWFSPuO6`76U7@FVPa}j|4^t*DZ4VBavxP=gS3vW@6iv;}az|Aft1*h=_59^sbGvG$S ztquj^^D~2o4bns*AkRYK1PXsA^MW5AT(P!FsyK9SQjCLt6&Ln!>}Mv z9J<-W+%`)YA8ugElKk`d87Y)ecFezcmQ46EE16Ig*dweDLtpaFouL!P)&6Zt7a^W^ zE}`|Xb3XA2Zf+&S3$g-9v10blgqs9wk~*RRBJ}yJVZC!7<0Aemkm-Q!+YIiQOzE%_ zIXK}4>KjxyFnA>w`O_}F;Ep@@9Zd6Q@4f67Ki|Kb+3h!(3JOdnKljn11H9sc!o zcieIP0aGA=?~^`{rYI`XAYX z?1DpHY`mi2%?9fB@uu**4>AujSKSPgJu;pG=H5kCZB_9lH*6f+cib6X+oz;5xvx>< z;YvAW=Y~VoCpK%P;>n+*_G74}S*R%zWFKMO1tsf0^*-0lz@> z#oYA&F8^mI3%u`~EX_M3i#o_uUc@pN@_r_F&PYCK-nse*`C$A0|3zMBC%Z%);U9tZ z>)OQlwNYg@`C&8of3tG)KC(^!Y4_1q>xFc^fsxOZ%o)~n{w0q0%0FhzXH_R~9CnPp zmG>dupC9*~5`56N5`tQ+7tsxR-U}Eq@sr1RT2hwG0MC@>h32~io;KzA6Mq-;#MX@_ z3F2|nty|PAyiBUYQIL(aT!%fB0$V~N&V>MHY2#@#_!-tsaMlZtFS2e{GZ&=b;=MHk z))CAjbQ2zVqx>hy{?-^yf=fFL)r>l(|Gazpx!p(GEf-PMyMbH&A;){~#yCbjeAKQJj(|jQn-vz4trikSnNacxu^Caw#Q;1CPJ}PJf`iu+k zSQo||ix7R{gpkL}02#BGHffTW4yFg~_WVqw<2oELJ%`)6W5CnX5aVE6ivXX?CjV_A zk1Mio(PO~rwoMx5%7qepAUoo)v$}Ky4GHm)7{5*65*SE4#)6%ZJjh<)B9NZJ;(w~i zjK$AtKtMa+d+#@;AHVw^fiY{JxZPnFJkYmZWNkURd-~4~J@3Ph%inXb@gLao5#UV( zoUvuedI|anTlmN1gOrCySlBamktoj&%LsU*7g^c?{&NHc-LRYYA0Nlweb1r$4LgR| z$s6T<4En+m+uSGdWIaT#WPp$~>o^gbbj2WCCS4CQ#tXfi1vt=(ev2aAFz`rqeBA6T z&r|&F;IXlYDALvQ>u!Hjx4WZ$%c{vkToI3=>k$d`+SL{9Td}@5o%H{}zDFWx@n&ent4PkA(7E!XuIa;6E_;kn2|4h`?n|Z8 z)lqxys)<8fF^CxcpS&CsIkt`^^6{JJ5~*2J-mw+J%NaVw;D_)m@~o!Mg3MW)pl>~6 z8lCzxArbrhPQhcaPis2#DM^;a4VEfpD%BB;?C|6xPu@*~$seTJ{o))a?LKKw*!!?8^qDg>rw!~m6N6&aawhgf z=u7b-bDb`I#zJ4DDL6nRyzH@f^%yvj`PDP&L|$>?M(*7cKTKB7brLx>zj~(l5P^&L zEco$KsGAEt`I**CFihPQAfB&i#O;i_EA)w-1l*kj4V)W-4tY>ykT%F79znw4^xd zJ@#v>n|tAXGgQ@APj>o{@#^WmBt@%ZT_VvyNy&BJZ|S=}WZ7}q-u06<8{f{{cIDj- zuKwNhA)i|O-z;5t+^JMh2=a1aFANh|WbPL?XV?z_O~J&F4_Uqr*Fl_vrW6z&o2*~W zOs-zm+GSgJ#m6QLt6KLnu)xSbD!u0y}TV0;km4i$6)RqKdgSGvr z#1`z@bl)p406M_E682pvg?+Z>;7(4F5>&X|JT_6kj#;+u{DI-P$L_7cj>3bltQaPHcX7tke#{*pejD%oR|~6_aL*6(!@4=rO0$>X90Kg(JB*WE zd524qzCUbnzTii8rUV8CV10y91|Vr;AnnI4+1NGJb*@~K^&@;4hfA~d!Az9N_exkd~#(dBjhM#hnpF5`i*#B}zc0Yus)CT$I zR%Llr9{YjHpZ;oJMBn)c`(0ITyX%68zGJ|_JY0^JCfnEFa+~NEA#b`G zXK>&OfQK~jIQq=2Cp+M(Qc7U>oLyz~Z6&x(w%R>fdG?A%sYjLTc%Y(SK&L4$WTf`} zZF$*)jZ&{F*Zx3x!Jt-CR`jRrzPPu-{gC@vcZM@VndjAP*B7@nGXHr293`85X{dSb zPbIDFPf6O>bL(K9Cx~|oOVkyXcrZ+o=LCi*#c@@_NE0y^9EAh(8xU&YDJo*Cu)$ni zmPDCjwDEc>+Wpm681p|pchj}af#QpIZLKP*SXYnMP}_Tlr(d?^-uer*!Imje zh{NKFBA4ogd%kcR2bnk8u3o#!WN+BGYqKUcaZYRfn(4bDC3I!|qp`Q^f@4F(mN^ge zz7M&q7WiUS01YstX~28(0Eu`+k~ks|IHb+Ozc7#YeWuvsDX(Sz@S3%A%-z?%w`#ja zTeacW(oM*CyP-Dbqb4bd>T8wCtWlwL7j22%4kOffoQ_i^ z5&>QXWF>8av!KD!iGE=?6yqgR(=c=k{dgdRm^L8>l9&^e!QP*cSPCXh;#88_jB7cj z86O13I|F9K?Edp)T_X%$i9~+ImeD)f`Wo9EOC#%FD0L!DF)a|}Tykgp z!fd5G)OhE&3OUnRUg&ojVZ(`}ZRXKy`5}&h-3bi`8F-U+nT-fE8Tczz>{y{3^YHB@bX&zsaZ-BtU-B~!2c2zl?!u;n>&WOb#z%wu&bu{fJq zah36$i1OGknvcA2nRKGX;#iwkKGfwW^M}wLp}%vVgE4-*{}*oK7hQ(~PGQme+~>-f z^AFobbOkZvrR!J20w2rtzZTr0#F{(p;d*hFj4zc9l=v5XCvoaLI!LQS8b%^ew#KA5 zCp=b5%ox`s?sKUml%qX|ZPWi6(FJ0r1Xbl|_hCC#JWB(eIhQ8<-NEjibSv*T_kHk} z`7kez_wInYoA{TQo*?Z4Q5;qt)EImaF@zS7Lya3n5^0vfPU+yJqAn+a#+Y4WOA8gsA+&X9oql4;pvHf2 zLys`D3hiX-x3<^CH!iOcW;UYT+}G5l(dhbOr&%PElxM14c}kT)L|F#;38zxOz@w}40daW{DvE(!Lqy;Ep#&XU# zEX_8E_LWOsEZQPTcZ#EY?t4e(zq<%RSU$$!+IrPn)I=}HIYU*Hq;fk&3a&^9> ztvFM^qdcFA;>K!feetwL*>K5Y99Fhw0xyUkPdg*(sP+Thi2UtQZWyRtw;{ ziR$snGXBHN70hL&+5$^XUU_R*_HUQH`8R)U^Dj#t9d8j`aQTZywa3{^7uuNLFmE}k zd+M84w5@#n`2AGp=m3&_bpKnOlUJAL+o8F@d-44xt&krf=j?1JyEqYV%@To|3wBB( z5igP(i7{8U2;STHTPP;$;)!mt(JFB_51&~mNLVrKR|LDo5~z@4o)QZ4uk+=a`t=>f z#XIB01r@NtVy+Rsmat!`->cymlBoNEV}|K>OBNTy?Z}_W+j8^aedle>X%OY`DoS11 z8g$Zc6xd9L5Teo;v#iZ>!G>t{^wrX;yDfRfco%Of*KAN)oFR*u*5){ZmbqWQ`AxK0 zBwAXKf5}aS%;O-~hNhLRAlUm*#~3Tv$|F^+s)9A!H;t|^8hPd`>vxP?6LVWt7CkrJ z$ozgNpmJLaVsx=tmG#rOQ);;s>H;5ZKr8qh5qu>$a^fs~^^Js3)6yTehS0 z5oL}wCop||WUQqLWjA>t-@_D9v?~J0eE#NGn9og9^H7j7NNn?BTIFo(82 zy%lEfmrWT1br~i7TbK{lHuhy&45K)00OO>U+!e5<9*;~yj5*UhLJNfh4ifdlHE^3C z0xCKo1~#0+J^(v4?us3qv309^WtS&{^KVTlJ>?|2KlAVt40PJuBe)9j3M;u zTe@RcJaXwZv{I%WjfO(`p-mmZc+R*Z&FR)=IeXK@4sStYQ11}&va}(qLT1X?y4xu4 zfP^152Pi|>#k~kx)*j9P_OqZA1RE`ojbyPdF!A7s*p4tuF%SntDtY0Q^hrpORA9$N z7$U3?hlWBnyCfoz00f0x*i~EbE9Si=%wH}N^_b+l_FdcFcHOO;uaf?3Wcztb<0Y5s z_8~p<`DcZGqqe5LjbW}?zNyc9pxkO+^UC8H`!y$n%feTE(wG}Y8w$!$V0aJL@sK+z za*g&5WfnvlN4oo#TXRKr|NbrIrQO%GF1a)F0p|_(Z`5R(m#m22Qt%Mcn)+LZZqN5r zmacy%+l=0dZk90rla+xF9_p{%xsrMRy`vs`$Y2!r zUhqYvzjntc(*5%2wB8l<7K=U;{m32iKFA_wXPmmy`r)AKwUvuLAVy)BK-a(Wnsy#q3X(!ZG2C-YqYA!6IzxZwK+@i z8;g@Z3^*qfyTdPnbH+V@8J!+?d(|Mn+?%FQ^bW!6(6;)awS}HN=APBhycABdjvUJYOdbD}7rH(v$kh@%@x7KMp4WKU zuOmT*B-qF7$j#uDZ4Bq_U3UK3mNh1Mo@@8O?#aegxn@nS+1%Fr=%JrEHVDfju+oR< zteN^s;D#vKov5d{CryUOST}@C3KOe@Du!!Ya?v#Pl}>IsymX}2>#BUxZ$G?rCBAy< zze>F&F1uC_?+)%o3d^yMa6$d}^6y&+f$5*g4Xy^u*GjtM9 zpX|*O8WP?58B%}{6;QMoL3Bf2lA!qTq|&{iBVX4sA$M=>=^L+IQuU)hrc%}=2g-n+ zp_R*b_|+3F`l9~x3gqjDyTTlPnwDbPy4MX@o;w z1lQ5jcPn?uv;gm%m5eR5GEdOB`RaWoFcS) zyl!M=@sGOvEiXGAnjAy#9kr)8wX#~+d$PJ?v~K&_b2hIk^)+CvH1ZX7%i`tFYBnL0 zORtc3Y#EXJok-I=QrEY9xU!_1C>j##32pRm=RfY68OoTZNtob;sl zCweBZA}fLD?;UF&uNxjJ`f+OrD0N2+mSB=ng;_KFD$qKz^80p$<>N>Y8xSE_5Vaoe z9jfcAE_)8PY_mG_4!;G6&XZ^BCLit{u3Z*?Qpen1;&!n0rWp4pxov!xpnMJp)==-I+`jXTPNQZ5MScXqnNPXfqtGFX&UQu=%`;F=x-jG zE^Y!ZLTA55H}!Hqca}Eix#D)y-u}I7T2`CnI`^*S;6tVykYJb_ivQ)%>zWZ2rMoey ze=ogOPyuZfnNz|3V^+?r>0*(RriyjPGj*6ZPrPf568XB3j`6yoA^(J0qc9(9gIYQ~ z+`rwgoNUiim*bp~&V(_TpATFCzh>N57zG1gB5xsV4dAzQ<;YhRMYl5R2feKX5@anA%i zkibqHH~*t6r?zZ)y!FU!!h1(wa8#CiimqC-W!D2O_w>8+ME8yzcb3OICDXZ$UEWu? z(wBMlOL*T52CX*c7YKHovGiL^!Ki02WV0aeRP!2hnWf)q4ix1adfK5Kc9@KZS$YM- zKyMAFnVs##zF;Ppghg)OLAeToBQ~zWaR77^uu+rNW`+yF@Kvj~wDfb;nR>UkY-j7; zw+WAo&2Y2n3E;-56PE4fsl{+YcuR3rsL4@P<|#UPQ+=2BC9d=pZetJcLtsN(GNCg` zZ^%?LZ_MS-hWx9W)_B5V4V17*Z^)3S0~S*#iZG|6E{)@GqOShm(3XS0r@Kf@5oCAm zgg7Q~2mRar z%Qn+mh71v}^fGc}2D5rhfbdSbe9-ZUOZCRPm24OXDxxPVx6Vk;L| zor<>sg*wWAID$Rh&aMfH^4s9B>gQyVV61mZ&_gp(@OUptLS?;6LLPc|Gfm~&cs#Ug zXj${<$tQ&?1}y*asc>+RX~Le*Q)N~2l!XDE)20tpNaz*Son1A{b*>fhj?S6^N?H-r z!!o&Wg*;6Q&hST*lXZ}BNMfl=xx@TVA@kOgnK6t2ZlI4j|`t1Dx{2%Mr5DulgCNMDr8<>x|sR}2!ynay$m zwgD{4L^RI!+!NlIc(G)2hX(*bwqO#fMeG7P5xG+4s$gI3u9eaC69sa2Ztgn|ANAP6 zHjTJ<{Dv`|ROQT7N7hC9YIlsG4dP4_ljRP3OENyoc*-60>a>DtshFAW>HsbrEf-0> zH9qeJTcL{~&}b?LFM++8;$E+<85_<T!Wm3KM|KMs?C3x@@D`PN&Y zXVO17w5`_fi9g9)o)TMOT=!8Y!T*?X9tD}oAj-h@lwg*1=BJBNsFQxhT4Pn$c-@Y* z=S!|`z~0KF%^@^l5hSZ^f;4OvY$Z(?4E{>uS3$yBlKry?y(eF`wrg*JVgqzs zSveKdkFM0mcKUNB+ja(26Ky($wSNawgXy)}3qwHf6Yed|Yh~`OP7fv;OV8(y8!Dz$ zu8pm$WbSjibn@Kpapt`_#1p&W@;HBj*?8ECXI7p`;*+1>#>9;Ev$4vI>64(F%L~dU zHIbcu*;-w6w_ml+U%;w99H<`}k~Z!P$fnwGfT#^@H%R3ZZKiPVdDF1LJ#-jwtXS9X z+K?Nblz}#at7Wb&ZfEZps}rxMTGl$HbZ@~O#f{p~giNA6r=uXZdxGhM4lL4bb$zv___z|Zi^JtrGS_Bp6uMH&Rt!~u2#UR+Y%BsolZ`$f`Xq_C z2nrtqHA;aB%gN?jYJ z0e|F zkA&8_58}}Jp`4k}8io^BHq04LoJ>U3c0WYb@t*9Is2YfO1qV}yU`P(vxtuHLMu=KD zGP5Lj#nPqdT=Z*fPcS|M{_YCML4x0+>~DXf-ot!Bk$UnB-d+-Zq2Yz#Y@Q#pPct42 z0m^ayM3unv60)vy!8$Gc6jc(U%VX{BrR8)et+M`{jrEmp^z=~owuJ+MaNCx)-rlz9 z*U_g5`=0(8HF@eFCky7Ei9Er;iSB1)#s(6g*=1d;rn&|PyQZc(mu(oTtsNVytsP<> z9IGrTt{NMwEH17bs~sM$tsNNw?jjg2MCzHa&KL6NtT--*6<;|2CK!dh05(cbw9>3{ z5{S@2n#U6;V%dl%;47>7A1;cwL8Gw=1s)S(RxU;WFb8wUGc@QRjskm`M+NNupGp+A zrqgkcK7pMi`HGkFZvtm&#;Q7DfoEJ`ApR5Zn95^t29KDsaJ@^fBv@-GPh$#5gq=i886|Oih5FuB> zvJ0TPG(GLWfd&c$Dd77o)0+tpY-h*OB!QvBt2wL*C}FTOfFhXt6$3?+a5`$5q9T(P z@|CglAHa5?Ad*aMYq9iUfxzLu>QS|hyN*DZ)h0L zyOz3}dmYTZSRkfKM0qwChy-Pm!F=Ej44-_X@xUW+EhDoqIHeoDKs$Z+&6}z!UuYWs zS!=XnZQD8R6^gX@$i*Wouj<&};Bx<5+#fU=t=)amit-|Kc+-uhaa8c}&99lAjYD3O zux@GPnpNoi%0ql+RcKI?_h^3M*ydG42P2%jX~bPe&Nh}C7nmZAm{T_q>x!+25$obg zZ@0y!Z=ilgj0<2;kn?jleIK_HIORhfGoq+Wi0J!HPM|Bg-ef*!rthXVJ5K(IDxZD< z%L9S8yq4BdU*lXQHZxWRu7vH_lX*{e*av5BV#7?>1g&-1@?YWi$Lnj_uAzEuv5hxU zySFqq9~PFURqL8g`13SK);Ta-UpB6Z-zdH2&pPXx=bCFam8-W~h`zh2oz%au#RE>f zW1o#!6|`t@O|WC@f*qjAj#fCA2;{D$b_(>D#3C0cCAAV;HmZG~JR-7q1QKgnZ$1+1 zQq3ps3m3cZic0o9G&T4$@0>1T-T+iMb+%3t?B=riNM+pf{ zVCT4XUPuufxo}z>^8f;mOfLP&sW;$!iP_zYahk>1F-gvm_%1G)C}!z_4548@n-9tp zw-Rh(dt!1aA<(75_4#c0WU5o4+-Fqcm!gIU>*reIqlve%oliX zkukEjh$pePNJ+4W&{{#?dTJQ2mj!DuF1B9wIkM~&%5qM9#;NA5!R@~aTHosGYB_H& z*c!h7I=K(=F8&2auCG^D?k&*w>=Mp@{sh5&GK~XvNF2tKa zE42+^i$IGS_EZgU1gzX)LBZ^GGQOv_6r_oq}TyzJ$E)OrlACCL}ZcxB2LZ><7_RC>Qo$!ThkT%woLcCV?eC z>E=GM-?4iy0axl6i(j1MQSK8pJ0afTv{b6YLdx zO`Q0O-5Pd1_|p!~&W*y#C{AAsL)HU;f!$o$lok3vjoQwdL(3}V4e~60p4PxEc3A?q zbQI-O3q+Y+zCggo7=8KqKHch}%U|?LhKip3*XT7`v84v_t?TM)&^@tZ5gFrbA{^l5ARlV>7k^isG&Eu+za+5{~UV6VA9Bd|t0FoTo_}UQtnW&QPbK zZ%=Pw_~{+I^;u#@^({P^fo}A@dv*;k8NGHuwWGXr>5k(vUIr8UHeR5{GW)4tQC`?X zsDxcHgVlr;K+nt%k+0aJ;6y?@ZJwE>Cjl3*OJY4Z3zCh$f&uDRKCP~xy4%G3^M6Xp z`eOy*QD>G)Q`g_z^!YMG{qx-3ctJF1Dsty(EXypLzhv5cnwEx^pF?Y{Yeynx-L}V; zRn=G>C2+b?cYTq~&Rl`6-*cqzfXQBA^zV!6s$;4M+A#eijjO%|>jQY0MDx*PP3(+_w2K2Pn7;xt^RSNv5feMqx1l^ z1^WphG9r3l`flbF1$U-n6d3_H#r}@{5cIySDYaJyWG(m&;&qLTEP&U&OX*tTkdEVI}b%XfOzB!{Kd|s!0MvI}`9FGZ@hz z05kw#7eVnliw?Iph+|^*BfL%$cFls>1iWAfEStr|hS$gzD_Sm`l4gn>G1&aD!fKja z(Nt@&JBAEWy4aDQr}4Q+`^L(i22Vh=k7dpMjFo3XtgImrV<5QWfcs{88b(aOH^RIL zMjd87p%v%q;eHkF$tdLL<_zZ3wcr2#TBOXlNn=Mn>hcjT*q(W%yp5#o`PUa^cf+Ah1A4+dl^ewEgp;EDmWt zGy)L%Cd^Iq;Nf<19$lxW4?|r9G6tT@i398)HzyHEn89zkVSF|SXDXM#EM^?ql_tm= z?t)y|WtGdQz(FNu+cTPk?j;e`^P^RE~CzSzCRp2x6x z!T19;58zkr{ngyR#UFS8F44{89(8HrCwhD0qV|5cWD8RV;9l+hP_*{``|oFNIx_Re z+sizA1is)*2$JcO^mcd}2K)m!STd-fA{S&l0XOPpNQQF}WDx;PMis&WAFT6= zz%U*=x+6r>>+hv$qOo$1yL7dtG~h0GyB*iPI}qM)QtOKpQmLflL90eOT3LED zRA$#Ji&m}n2ij_^6`J&_5)sb3vKFI+uaIj)W=WmZx2VAyF5`eBJS`O zx6*>_v5NSvoI759c3n#o|DRvI&k@eZNddd4E`|K_HBgr>;~d}|WTi!>RIxmWOt3`$ z7c!JVyb3~!Kr#pR>JZqH0QQW8%G}auJQ%RJmuns7{Cu;WdFw2M{B_J9cUH8P2J(uT z8^2TFd`-yWa<5S4`s_tdlm`-pFgXUV$jJl zIAeMW*7Bz4wW<`I0E=n?-8~v!2yo+M`fYpe>%MD~&J~-Uhm1`-X|$ z3>%;X1BnxKAjp6YI|Lf6cY*EPXF7cB$tQhC#x>gXfRc_LSKiv1rB3 zN>$xXy=PNAzR9ECS*KFoToH{qY-K&QW9L6u-?A-MQB+h_vaO|lTKw2!kAZ;v7d+z( z4BBEP4ozIBN20Y=wO=wTrw4g^r1T;nK-*#-m7XD&EzU?iu1nR;}9 zsp9QLCkdMz-VC33znd6j=O?p=SdU3M*z6_lkisDscp3maDDcR3^1xwYX^>76cB4um zVt(q^H~I7Od>%uKPp|X8UAW?n?aW_=pY`5UrhDuAMHzOHQ3wZ^UO)4Q(c7x``X|p>{rENA`}MbWU;RRVCvuM|lv+`xzp#F3%>`WzzotHA z=}()XU%@dz^w0%$2z&qW(|I%*+egEM{u{h4aB9HpLvu}Cdv?6u6RYPrasuW3+uDXn&P5yz9;}$-{LkJfs^^L|k|L+q&)Qt3=>=kS zrizLGHi&7q&g1?}8jJ|cjya)|4_8++&sSIffwwU+o?iR1j=VT~Z@edSQEqH5^3!W?MWr~sFsFouKFt4$1QYC@-)a*B(Qrx>TV zLku^KUWD`It?&g-Bg9ot2N!ri!UkhRu*m@K5yntZLB=9V5PI?Qh(sd4q}P#?-Fpd~ zoD#XbH#^7C%S`t=L}IuVky!WlW{X9R-u+eyq{Gsj>zI3}qf{x3AQ;#TH(c8VFjfFP zCva^L4X__DjSct}5j*=q9fhOS`&?PD45v6;>@mVyw0>KGOLOi&@EcWFncmYL`m3bB zJw)HYsGYDz9NudxDx+_lUxVLpzsk$pgPx&&0{LxZgn(d{KtdhFZz|}&L0wHCMb8jy z6ZzdTZ%{HZgDZiC4yk$`4Rj3HRLpq^9N^0_{A7mI;j!W z|772keH>o@^&9!0e?NPT5X-^z4aeojiL3{J{@3X5v3Qg8OXlGOlTFaW^7LAQrzGM8 z{v>xOHV5ep0n8KVZ5A)h$v>q-T675TTJaniBv;Jk)NGHc6i`7Fcrc702aaV}Fds z%*Y40C9DOLF%`)SLa<+qimflm*JU@bh}4>@@8w@ClVt?VjyjVQy-P6sMS?g0`bXNF zW5F!{L zAY_LSXIpw3H~|S@gq63jk{ULaE*kW#sw%l;g{P&onxIAfLLv7;?HhHWp^BQc=blR+ zTDpGa?OD%0&GiNv64()A|KWq^dFS(wgYED+hEsRa)#xbrplaB=X_Rvg>F2{(5Ie0& z+NmhpTH%hGfCN<#VI`8&*hY*@hLZs#wyOu!g931~j~T&z8+ep-_GY&WituLF@2Mh? zM$bmQ5xTmZFXv~MW$P(_o_j|%Y#s5r%O8tHG}=sEo;NcsFHN8mWR)26RC0~Y^2Kmv zxj!`0wxlTP@^+4+gF=02x}<^e7gr$m)%CwQZ$-pv>FXOZKj1eQqf~^#JVDZ`od* ziey|02{T0xmITgHn9nQLXl0}FMT7}<$>Ws6yv_-*%UsS9&c&SDIQJ20vR26t&o@gR zo+!sv#t!W?D_9UY)R)BlFl;)Ph`1CWeDVSt7vQ~^lEcR&{ZNS;crwo(Ltw-36$jXf zt^|GzCaR(RHwnT4K_o2Uo5KOvnL~kh^@`$-9T+iG2JVRpuwe zEnYz^eQQY&>m7JKxM4XctTPKSe@Pf?KR;4 zDxF0mJmIdga&9^8fZ?Ok?CfB~Q^nQL|hE9~v)!!ssepvCUqSW9fapI$lCj_!MSN!LA2XKQ<#{hE!%CW9P_c8_90l9@;NbvLo1^H?2dmES35I&h;Bb-*9#`kLDG_J-CiF{JW5`oh z24~N3^KCd62VhYgnCF5`tAuDFEXY4w2%X|E|Cj^bR1)usu*gI#GOGP#eJZlbzd0L& z7_mmd^#kH0AJicI3XHFwA@0Sg8Dwty7HUkz@l-+N+m!Sj-+X;K+A6-7E1(%VpXMp? z+PO26(Ly>G-oZiD(@e=3Q;uaEo}*Ci7ymkPCVb4uUaguVds@w(fccMqns#PTHel7DbdKG%( zcpgn)7ucf^$46BH^r~;q9^c-*0*RE|XY;P+n>gY_9WmQyU$}1{lndSHs*DH#% zj(G&V0-lM?pCUYNfak1UVeUmsOaB1BEoJ`m4}SoDX3KGKDYgXu9bl9Kum1#IDQNTH zR}HcY&_9{#4=%an68L2=bM(_sN!^$&2c=}B2>zYWG5Z^VA%Tr7aRC%zPO>mQ{BR)* z2`-WVv5*c#hj|3XGl5hf(6@m{SbBjD#1>(p%;Uu>LOi1i{qutl&=~XgOEk=0v^TJT z7bt~`kY5+_0vQQ(*f^JtzbxPd=Ph7%pGnfu4R-Md&`SpNMA&{1)E_(Ef|O^(V-l?I zj-Wr#0)8;u+8Pe>(@`(;0R`K{+KY?rWa$`N|=g*5Ko{&zkA_@bK2X_2?^Sw(Kf;5cR%@L z+r&gkL3w$>MSySi*_kJkPp~Bceg|_q`WWg#25teN76`()!3zVUH0k|;15x015q&(; zG%(NvXOqG!m=D)?H;!dkO`A8HtQiF%<^;SoHiin=Tc8er9S7RKfYA&wmL=QKApJ04 zfeh-9AQdwEzgXTgUgFLlTDJ0ho=qb)6$W$B@}`<)>J{Z~^@Wi1jAb|r za~{N0D6=kZ=t!uo*7#-B4&FEk?b5hQ2JlRX9o%|<(KUFCERD*9uw@`<*|^{wOM?PF`( zS4}@#S-G^L0{w^9T-u>E7k5G6a3Ql3UHHw)k}Y8EebVJgO_0aK?AFx{Ji;qn>C3B7T%VFp<{UvDsEmYgBQ zU6K@`7dirqC@+_*J@Nfn1t#=IV9(PZK%NV2R*3+F=mvC8cfzv>0?W}&GqzReC{V9%X{km_u6yI4Y$%jey=gbnD?Xl zzAioe*2U-UnwVM|sGYtk6@QCQTmI5LWu>93pS+FRT5E5v^FqD_SR2dtKcJlova6-P zn<7jVjfp10P(>6W>*>e~2$r_Dcgxhdrn0fZi@Dv^HC8QRKFC;eqZBPlDUVvVyt8Zl z<$)S+v;=nQTDNK>x}>42yuumE`1GfD4ozO0n*nrlS-N>&!rV+0GCG>hOqQ7P`PAdh z4bFg*g0zk+G&NaT%uC~7$!=~-Ri#yjGR}-GK4+@^plx`+ueiDgv(^*{QM;!`VjYd0 z6&0>f#$Og^6WU&)AO3#GU%{tAcX0a7j#HLfq8~7zR9@#^pH_nfX`Pp9E3;KB=WWdA zsHw8jrlrt8;T~>FWtAltr4JWf!0oQ7&eKx-gl^Z*SmDW8E974{*|Fcb;?hv0vLh*o z;y{RAfB$2x-IZ0Yu=GEtRumJFIQ$u3t{N%oZtN_tFcm4jN@|{-em#+sL4yrIR3QK_ zC`9oFDc83*4QgTmN|Jf;u1e}>ep19sv+$SDIu9DMM^$SN;2274}hOI zH4f!}K*~e>i(%p?=01g=q)e$#CIJv1Yd&S?JbCIzIDS^8#Kcc}bvlnbFVAz8&g0SL zxpBjH>cFYXQ6BhXoM)Eek3rqU>!7@Z3l1#ec)9x$?v_K%z)_MFZnOS22?$q^6c>x~ zSQi^8_!h^?-FF&y%AphZ{s9pW-Vr9%!>3}L?}U;rbO!wyI!@lIWy`xdztdfExGY`Z zFY$^}vRhtC+cTfC`P8MliUpMZJC2b*G1Y#+j@@B=33i9z1*o-C!(|;!9jAAPJm6sy z$^&0$f>mmTFqRMf@$cZ`?A+gs^#9jRkAGsa;}TcW)y*(@Hm;5{>+5(BAHp~j%?n5E zVHyoGhyVQNO;m{CUl$l24y64e)j#2UwS?bDUC|&!Z+b{A(|MS~RA~AWwyJrABjn*( zTnXPsLnfvWt;1bLrWndURVdsBC1=Y~#0zq0GdR+p+||ka5enVf)Ec6&?Vn-v_U44=Dgq2neWOoHL-vCJiWP-{8ekpWY!#{ zR68`KGHH!TTcnUxn{q3&B~5xwsZ?s?s?=J2OeSs2RaeQgYW2Dbd1f8BTcAmKs+e;> zeK%gc9Tfo9R3cKZ7bl32sEXX**l5s~ETF5?n5+5l!)!`bcs6w90XIq=H^q*U+9op^ zu+Ke?{J~K2009L)Wzo&HTb;Fiog{2O>8r>wwQz=0GY#l2;Oc@ z1^GgGUUw)yRXZ-*)O=oBjL}jdbd_W(P~r6Y8j5(!=fV)eiY#cCXn_^xCc*4fG}@?U zP6YBq!n@$X=iE0PxYx|%QSqW&s~Ubf-*Z&50{=RdS_G6<4ZN z%sOC1>d;%41-Rs$*GT}*@}hwLGDPMqJi84iUyv+}Xap{WXuPp75GZU66grJYXJLQ| z0Bygpsw5JX^@T?j;`DT};!*Bz2~0MYVCz&C^pbON7DTdE2@)LZSuV-keDfRd!{B>V)iD~OrVSvEr&%|PQ{6Nhyf?tN&Y4q{;I@Y^S|h<=H`zrFyQ6z&Q+fDzW^ow^U*k3u-}0Q^2sj^|xLFavbIT#@H;ae2!NX^|x0p<9Jql~JzkG*_rR!G=%uxjMI3i9S)e^W6gBry4nb zjlwdDS4`mglMVRR13nlYU}?wL*v=R%o4Ns!`hSrx@G?}UFJfhrda86t>)?n93P zZWxzGumGH#ox&o;9AnnmY5N&-!`wc~{L#`7&NE1;g0-4hR!&*E9;pgzvoh5JcY~%h zJIf_8z*yc_G?((px!iq`h}8QrB@)WHnSEjKTo5n4e<};T0eH>O<48!^E&v|MiNjI6 zG!`UGz5qfpTMjos10VwEvcFN&Fl5QGyVZAP2lffL3Uj73tKCwe$`5Xt%5m7J>a@Ik zpW~U4CH?Y^xh7bMjxJWH_^ajC5xc!z?@NEvux=$Qd(buYDbUd{Lj~)xFtRN6WQl~n z0eL1I_=iQZhy`F0u_q&QoYbdOtlO;Cb&2(6gD9RI@KABFOrtU=k-;kW6Z4R2)TT~z zBWy!CEGaCW>a`lub-4vJ_k5YsnEL~t!eTJKobM9xU$$w~a*d0cob;!dPAF7d+*9zZ zsxucfcoXw4^gd$9x^}RA;+!xwZiEkk$6f|Y4UT=ni-dtr^nTQwk;YZpBZ{1=vgHR> zhHVmo%-k21X)CG@jG(82PTk!~%TJiMs|y?Uph~6XU1F!DoDb=GG!0P#$BUqsAx3ol z$uH@Q>3gZAAMVxe4Gav-FNb(xD9Xd-sHM~Q(ivz77YppgeFGEZy!;48DoKuym2{cO zFoggFiHRkXS2)jy4aTG3cNOSIhMY=WVeW=y;kE)_KrL%%Fp6w0S7^C2@DHUs+O&Fm zzRT76QLv^8PN_)0D(DHIp89YgXsPrHHnKX$cpn42cyyGF)bYT`EJ}h7JqBpHqDeGH zaZlUs=Be$lieA9%O+crzmk#w~m=tF<*wK6FS1`W8_MBO0wz*ydzLNW(18gs_>4P9* zX7f-nulPU3`S^?G~lLMVcES(uhe!}Dpj6< z-p$-^B)De^I4x{9dSC{ z=_WpUU!xGz+7&d{Z+FX;mh7x|D3y_i!r>}c)+XrSaRST<`awAJ0~WE7c?THWz}zJk z?&F9fIiJT4II|UcHqDlPa6{kF>Yko~VoySGx-^u$my}f3vmZqwp;TFQ zKlgEDRpJH~7NHCB6*F)QN$4WY2^okaA|cYjHi*T7+X8H%ASgDj#PUPWEL6gLtvrdf zIakAk#)T>-vg$u|H|G=dImF}~+>(d!xqXld0_yq1ZmiX)%sIw#Z6o?KtnlqL7~m1` zd-t3=ih7U;$3<2-an^pk;b|5MV~y&O67{6@iKQ9B%QDi_)5jmjmrrHIGK3RZX}d%j zTUNi3m39OWCSlzRuplO~;yO4FQZP`C(7gmg3NZHaY5}^Y3oC!QrOG#iuGw+P>gLUkn;qM6xl^^A&j2rsKR`SWNuyAbIPfsApi+L;;+Dyk znKFY|D3%7zx{l%_u1F;Av0L&*tFvlhMw`HB-V-`y{S1~AETb*&dfq85DRD~b(w&x^Y*C}vT@Y?xdV|)u@?q-|XO)7VDbG}C#ql?fofsmgX`<@tmcG?l@gJ0n zYdbm`N3+^v+abV&oCVH>R4X-v$HriWgsjzrEN95Upjy8QycGz%h3u4{>G|+O^!wLd zODPZVad{fAs*p(%r7a(_rO^m;82z5P2;n3Pf&(=G4j5y!VjM=)5cmq&FNAqF_?_lB zs1DBCv=gFrEslC+xRvCC>aeAhCs%Sq%V;*~P?S9q;_YmqODmU@@DN`tOmk_a+3q@u zYpO;rns1`M%z`$+B`UP=R2ga6Sz4FSQH@MoF3oj7G|0G6`>8vrC&)Me$z72c2aB1L z#b_I9f9WMO1~fD0q0&!BeBu zevmimX#m*?r$Y95W1ULmmc|gCbPF{WcntU*(AWJ4yrUIgS!UIIRt3%&%ONW37}H1UdH-Oz8s1ygJvKY}|VP?0fBIBr+L zHhl^b&ycV182(DmTf>uFq@Li7yCLY0aCejxmK3gc`l{Pad&ORdtxhTC$z5wadCv}8 zZ2Xpz2BS;hP(wQ&o*3BBTi@c(>+m|1d4_%7v3RUeCZP?s>Ri{hY`fFX-O=!B+P&Kj z4m&DKe9T`I9=c3cQc~1hS5(ozd?>F1S)>8OCEC(;g@)}aQFTKO-|DOJbvT2L{Fr-n zeMO|CJ1?+1D{Sq^9Tk~38%)C@I9N58*H~QZ&n@dLEwHEUi*0w=<^5By4mY^guX$J7 zm?iT-JS0AKl*)#^B$nf~j8+m2%r-8z#AQODBr3wDkw_OzM6Aj7hKMp@Ibi&W5M%ZV z&%@%IRJKi%S)8rd;?VfB)w=w6Wl*D%Msl2671C&Sd8wj2UAfbxhBhrX->p$Q3iMKG zxNNg5vshK~9|nuX@Q}uxugsQ*G`8)Ubl9RGA}^9^cDQrGSqho2y38w8OY+sOE$XbI ztXzv#ttiUSY%Pmq%G7~MgBh0YllqK!)Ys@A*dHOIT>z^bqN*VEHS_UM|MVyO_I`?Z zhYuUxe3LE9F;K5jKVkQBp7EIEg4oTxD?F}3LU|&Xc~`jIAh%#gq1P(mTnL!NFUoLd zn79?NTFK2VPq(J~XhT`LBi&0!MQ)K3-d!R?8XbdMex8xKteJ1-!I6VOp-I@7=}mW~ zm-8#cu10<&&6HLp&KG$^e8R3RQ(0QAqQ{1p& zuZ6RA=O__2E}D0TdMnf1%*_|%30gBv-6~6l8)&NM7g*DCe8LuiPiPc2K}Kzr*q3HV zYZjE|Ri!)A-TV?D(QZ-UcR?iGp6(J0#7bVN$S1P!W5BWvzc~d(@b1DfyC0?%zM!Pw z-+>`mZ4a#sM~*-dKnHx@e)Uqq?o5%6jpI zdhp&mI3J;VsLYgA%FqVz*#z{tdstvsHM4^Sx<@AI3-n23iH|z5GvE~88gVX*h|!AK z`|z_<9ErfM5wSSp#PSzFt9Kpxk{TfXb#~=Bn<<^BFR7ju@;bhoo-Z#R9K0C60+Wr6 zllZ0m77DkqWiK9Ni%u4N3&j-VJL>6L?v+3WY48CJs!LwBE>7J!>1I*4q09^?4b30G-EQ-y?8x9Hp?;_7epTJlt$iw;` z?qDU*)~$pMQQe{M`ee_yW_1bGDLYNl8))mzaUW&4Tta9oiRw1FcpP z)R90Z3+o6s^Tgke%!NmuNj`x=9ti+UQZfOTx(>=HfyOzrS1<>e=rb!JpGrktx5rr~ zv^=)y2s{k)Sj{ap%ol(O^<4MHB{^&s!8ZIGH}n48ef^`;mtispPYL*^gT4sl(*Xr3 zf{X|}HH=iicvH%pN(#ZaxlEZTqY3>rPMnWG$e%x7_A8+ER~Kz%lMxs(%f_5}vz9uN zhA{m!D_o-289L643hKIVqu@-iV;c#8o<^xRah#6#l^qQPa;YDZ`@7-(+LZgd(O=2^ zkKn#A<^D&=j_;#d&M3MY-^cr60UT7j;@j?XUgErnHsKgkhVu!7FRln&jVgCN0uW4` z%Me426CVOi7+GbpnD0nLMTj{tGI9XF0?8!8t6_e^jkd9O4~(#xh3i`3CbrR3_@{-w z2-F1t39UY$^*GG6=OlLS!v2ii(tz}y!Q0s-Wk?_)yB$EF+8^jYkGus2Yib7Ht{EIe z+XnUvmoFFYA4q=IO$nKU!l_MYvv8`eZYn|Z4?!jZcD)@N58_@aD;SbrjUzh<<4_6a zerL@vW`DTG5^cu(H%HMnxczoD7F4w*f<+Z!{REZ=h7BzaZZj8w_`?Ojez6FgRSCV} zmWy-clI z;D)3?nA?Om9EYo-BsN##Lrqoiv^$KY>Mt&uT^EM5ep;{)i6)Hq*|(&f@hSt z{&#S0qa?7m5A^l1?#a?nl>}={fo+MBtlGMD6@IPR+~3_kxOvTUdOdB>>zV5fvN5Rv zWJv>zDy|1$2muPNulQ+pc`JcPZ1Vq*_8x#yRoVY|?kh8sKFMU#%Sy@ntlMF9atr3j)@1O+R)qSzH(?8;ge{JQQc$z1;D-1pwhB!J-W zFAhw3@1Ao$r{4Q+F|jt;w?h1+=H^NEcAF#7+Z58HKI;Amwr4bg^zO-97rn#iXW!~{ z-}+!%AUmwhL)oRiv5jla%f<~|&HtfLN351~#tJ24WSLwN-AT zO-OAz@`i0okay;?Jzr7)>Xoh*e1TV-mkIU(bHy!Yc)_ep8{dL&!}f;k#_bKeY?zV% zJ=m~48eZ)W*uX;@`CV+2Z3MmA)`I<=om;VO;;fd56I*6Yv~x+jE2!9@U}jVYJdGk4UAL#!$E z5cf)FeK{Xzd;{cmUS)kb5Xpo=Cg0zyq%A zmTx`%RMx2DFLIq)+JfH^cs%4@A>l}#!|5;~n(I%GI>mf$R=4}K!i$Rc?@dWxP>_=sUv)GG+A24X(qx0qVPb(Zea#W)F(t1(% z?l#UNOy`kCK3UT+XKvl#31@N+*K{k7JE979ih>!Kkm*>L z7{?X;bZI=!Z_wi43q*LGG@yr;fs;o0Ozwz5oSrnJB)_G1#=!oDU+&GfQU{)Z7y7}i{!8c!Bx7E5A z4*dk;AY%_52oLIDH#sRxEd1$r(W~l_;N3Nv z=Kt$p_dmvIgub{Vya+1R>Lf)Y_MDfN(;U=fY+faXk6PI~D^gQ6a~E+TQ+1}GVe8#_ z`W^k6S{atjoJI`6HVE8=i_6TIseK{kq+2*mYGl;#m7~JN#XB-I!awLWYNcP%?>P7M zwLvCtcv|lA&`en;wOoUE8tNBl2h0LZ4r~G7fVtHOjW5?wo$;t=RmpL4|LJSOi=SRn zQoe`(H$D8!p-ufqRXj<2;#H@fN;tYi$k_ZgjA%06#&deHneFk{nKv*p4wz)a#>g$F zPmRjzjeM@!?CL#hyST}HvA45uj`8~w{U^`()#dG5MOGePub-m;0p4F>tdL-|Q zTX94a<{rX^@M?L3a41VSz1Giy+l9k(hxc9m&oAzsZ+3I;S5oQ;X9MtG@Y?V~I_t%K zq~?czp7c~l&==mOzaK0k#r?yR0`d7=zgw@1yTv)IZLJe*F3g*C7TD+7DFdFl8`NeV zp0TGHoW$L9GySRky@iX9OgKT*SBO8oc7^_VV#1Nd3*T!edNPIEOMilm-l#R7jMknf z+ACLx_Pmyi&ZpLcbUVYVpHqa`3ce4cyu`?Dnl^(#867$LJ6A zbCN~QW_5hP!;;VaF&X2h)yO3`XPDvEZs;~94C*{e-I;`^*otETEqhDsW$6QE(1<&7}v&? zS>NMeq9n$Ye#BpF6=uV@4-_ZZ7EYVOnGXgpb%xex@Y0K|H!qNzTx9YG>&OG^>F@NP z#Q#7*UBKbGrCX?Y;S{N%8+OaG&x5vJgB4y*k&G?9GZ9;@p4O+~2oM3tkDEu{-%mb# zhHjv1P%lnX;QDtV%j0-I(1z6&t!?d9!qK)Vh$j!xPF$YN2#{L^CdL90#+f@1=qIqV>T=MY7OECeU zhM%;-6YI8r6|AxTl2E`fa1x54ZNMOgV544XLUD)d0q)2Fv7o(=@HEn=%S3}X6yifT zpa4-`gaRYN9Ob38WEu@D#z#Tviz{IpKT|(C*ZJ&Io4qQJ?l!&)7l9Aak&jAp%CPQF<_&~ z3xm8DNfQe9TWg-!&+R!bRJR`iInN1&5*Dh{aIG8KH?wW9YxrMvnjSnyzo0*yrh6YJ z1`_-P2_<1-!OaW8qV^?l`yydUd$X_}z+t+&32i|1LgzroxJg64r6EtjG$wGKn-}2v z65)(=?Pieg2+LvUMH$ZE(p9!*rq&M+(u2onu z=k2yHSM3m5xqqA?nI!YfTjYVrpzx53%?&!LAsx=+TRsjo21k&j{ad%~w_%DlBVlTU zmYLNYuvQ=7`yb$TSjY3R92BDp9vCxVyh92W!l8~q$N6Hbn&Ee}O~Q=dCAEiZ67{S_ zewVcd0>!BVd~e|>oz`ZZ4p%T=5JTY|JL>>j6k+4vQ0n?Eb>-VTz9elD#B19x+353+ zO7ubhfHME+0c&5_#u6wizO@N{XYt1f(F~p{?$0X$Sgo-)bU20Yz0S`bA6XTLv{a^ z*u+PV)|=K+8?Rz1+zYWAC~G5u6(Imj7St69b_-`sdx@n7=-mBuE<|PGwV!xxUUioc zE{Aw%Sh7huZi9r-DjGL>5x4@x?c?nK3I->q*|BOn&&AtRfiaTDYiqrn^nrBs@?WLCN~Bjjcb2x_**5o4rk#3R}r`=R3a zVgF9gNA~GyF-8<-^E z7DMz#0}rO}9Rn$geolXYM2yQ+AyJb65rF%Jrjh&yX2p))5Mck=d9%PqOh8%;GSdgad-?DUM#*%iYg6m+0-u zB292R_uZAvM{5Soowj-R(&s;Zj{ES;?CS9?^(%K?AO24Bh@Br^64H9tHeQ-jGuT}n zaDL{|+VYC$=OpD!Sy*1MR-d$UQ*qW@g@tp!CGz_>YY)8g%7L}tkhSDI zO@O1_n>O_N>?VEr>B_0F(SId*pLR#OQht_lDD*~@EXqSrR5B?SEyagl;M!^_521HRFU&)bUfVcL+b{e$Yd-f9z9fI*p97qkwAi-v z;-Bl-DP3dD=b_5e;LTF|wmOT&SD+xawpX=*??I($5XMpiFwNvsVzq=K|7gdd1Ke@Q zm{nbVN5s0satWUV;7jU@q3QutsMZXYG$Em_tZDX_+YcOAbc2xBcwu&T-|&&`kB9{) zPRO*60|pyetzm>ILRzfzpik?gW~iMw@jBihj65zkAT_68?Ig%_fiGrqcsG<}K=;7* zFK0KEwehbJa%0f}VdThg-|nv?QRMd~&@7g8q~I>0-rB}(yvg^LQlKKcoFgUKnf$vB zSWiKctl@ie8{0@LrZm=WnfRjc02{}EY7N5-^j^}~x@)O+m8BD3eBoJoj=psIrRFzJ z9NhBT^{tOFIl1@fg(vnMI6`u+d@p?PpP%MUnYQ2>!q!?oP12LlDCr+~F)P_bXxzWi z`r`-OWb3h4xCi%>i`%Vxxr^K^sAMk7eDwl(|A#RfVu~}%L@2JXzx|VWVgZ*;wa3U| zvXGwVe5h8D#dc35#388YvG`+E)NmnsUN3UvZF1un9YB|m9x_e>1>WSmfW4G7fyx(H ze}>CtYD^BPZK&1cwrwr%w>Lbn6Ys39V(?Me8}k8e#d%{ z`_F@L!9e(}yK=vixDhY`e!#Dow~8B~TXX_4WF-_r=v@-ufeVSy45cL* zK(*XJ(o1--{lp0JeH(0a(e--B6F`|5g=VTH16JZqy|{tgMjD7^DTPP;$R|C||68oa z_KBJ&(CsDsznAT?zFj^ihs(U>)Lqy>|IPg~*ZKm%&LH4u;|JO|6F+RY=sTZHD7^rZC=xj_#@g-kwbBj00@OgfT;IkzsTO0X`)bx&St z1szj(^*UkBI?~heci@$m;~`uDCqls`MX3UlW?1D3~9b^Y0XT?*Ubt3tw)VAs@%Io+N{y^@e|0TJ* zwBeu=Y)R3uy(JVCTkKem@1*wHZ%A53nQv>)L1xDm5m9@qC?mG&h-&Ay(F{>fx3zDx zA>>s-RBBn_wG+RLS@st+b%*vG_;qX%TkhN{wl1L{BVlhDEkJ$8wsDM5=2K}Mkw7bu zY@eYZW9(oJb{_y(6hh}^*zZRUq-ysGq|zC4N8eCLNOl4qa^JF`94L?EE1jr-Ope-R zKBEv~0?Ce}xeIRatfwn-NKMhWT|bIk4(N6ArA|aaMA@P4YFmn)kQ#Cz#V3>vUy=pz z&G;Tdz%`q4z+C@IFG{QUuOf%NWyNys_Ql%1Sq20c379u_7n~SMU0X-KQ7?813Q7_M z($9`o7fR@Of8i$zB?TS)*G|RmBN9R~T8=nj0KP9-P{WD^NZM9V!hh|QluwE_K*ii9 zd(69seJS!N)Q}>|WY0{fX{3ROIilA&Pcbb?q?vWY+xwIg^>k-6?K+ZZNtoL586$}? zfe{4rbNU;yB1J_`$$L>ol$BAnd9Q<%O4?IIMbiW^nWR_--X5!!lV3X7C?c&;SJ3XP zU*w>x?2ZU6EOe7C4E8q5*{yJNkCr+TTeUkod8a2emUaSbhAraX>B zjx_=PX197Kx@`B7yE(c1MNBbE^??$<6^$sIC|Gp13rBA3?jm-{h_Zb9`ov_pTwj z%8GKLy!INRGgZDBWq0&?=JB0mwRNKJ8F%hP9lt{^@L$P_x^m!vHdwF33x3yy35Ecw z`+j{9soH(fZbgoEE4>FwtaT;E0nYc-tJ1onU%Pyclsa1$eo|;TbRO=*e!EgbxkMYH zjubni>sXiFPWfK-1ImOiq^A6foYL3@Apt58C!3T6E6PE;lP zwMPd#!V+ab*QEZ^I z2JTE<(u7n+IBG(%@cXMHka|}R6fEo!1+lPm;TTaIkWj*kBOH!Bl>4Y9?#7LxA^hEL zBaR&5dpWMKksC*^z~3AZviqf6P25K;5M>)tIKhAIvCfflC%v#*TcU02CxU|R$1WTx zDiO%8k*@MeIl6oXg6M`;B-^nR>u@>$-N#<=bYnLDawiQcoGDo0HFw8L z%0v=h(%+6=hO%@*&hBhVp!YM_a(0q!4*As zrmV;)XLE-U8b*_OfUVzkpYnF4c)LEkQpL~qI_oydi1j^Vfr7Rpb^I<8UQ&c|w5YBe z*ne}3@qpH|wC(i(1KjO0e zHpp}W^r1Hhda?Hj@546~%{X$RyhofIBG(;pk$l5ZKb_;(ZLBevFrfY&yHPm8e--WF zzg_J{iY1QGOyZ_f&!iJxj2&5Z_gjl994K7jXM7=64$;j4FSKJN!=cV38+JfS32~j_ za_mFicb#=N?iB3qY-5fbI>flY=us-BZ;u2@sdc}x$kFx`t|g5+Z~(|TMnMHd%omE~ zE1)rs{+3-ia-c*+y9V#fg%TAV;zB1z?0Ebgd%6=Rs4)>`~NiQ@3L##ZrkwNs|r{q6>ghoM#wH!Sw$Jj*i^lj-#Dp$qzf( z7^~N1pR~tSgp#o)>-cZSE=L@d_o(GN`KBX3N~EyISUJ*ymvjxWcj(Ky-J>s?Wbe&7 zVs^Lpcecx}csf>>w!Naz>@9>%>Vmdb(VV!=iZ{tNwdeu_u%Us{N@ewFz2$l zd$!)VeLfs_hV@=yzNS+?%)9I(&+)TeDM^7bMtSiY@eYZ!6U>Xe)c|t?!~fRYz%gltJz@7M~q1i-_3)ge+#5<5;H>#YV(VEDt?e_m;vaQ^%@n5rqscdLOvEbE5- zO5h6q@cHv}2)pWL8D0r8-D(gA*mP*S60a5qNLM@DA>GC1#DeZSZ1({g$N}D^yi^_b zySua?wF0`o)u1`x&;}sVwH0hlbD(oecW6!FtBd||%?kR2^}u=S0dcmN`R6Fr-t&Nu z{W>;38Lq=W>{>b-Vi=vRTrJ&UzaI52T`m8O?LPyzTs!}a<2?@dY3jhfQQMvFLy8$j zO`UWv+^sf9{NbI-3wh=63@m7Ru#*9I^)!aV(lt2$IL&NSt6&9{Uj7XG3uVHhdRQ?B zhY8M3emTYRndOl|w6+f)+{EssZ@3U`#~dcTphgg z7S2UPw5O0-@;~Yf-Uu`WTqlTU)WietxLyg)ltrFlSuZR*!OaAG2`(}Q*MXHwI_WK2 z=X-Ne^NEfhPM_w!eyVx-pgwckhL59%15Fk5i=RfP#l?q252UXU0m$uHAyI ze{n+q{DX`7ytL9PU)v8k8K+P4?fl5MD#lv>=#enX z`u^&;G-CZ7Z3>7>bZ-49P6FL!Asty+_7#kGRUs^fgJZrWWu}RfRt5Q$7lhTmps4f7 zb@QDK{yoE8;dJg1^~?Vc)H(IfqOrf{FJIgvY1pVZa+;0~j1Kpo-BqzZrqvUtfnvV` z#h$7yyfl`F|9~~-XRw$H_bG=>5STH6pW$*dM#WHDX z#z|^9mHwH9p_B1BeASe8io9`B`nf6nl+^2?bsnzFOM$$04{33r}XVJpmU_}8Efh#ZJL?tp@O zXMo!%yUW6H>UJ^s*VeVpe01sP=Gva!hYZar>TeGFwcFwa1xZ6k#R*qB^0xOc%qp7G zb4YFX`sl#EdA0mG#xbxf;|HtqaaS#cUx-Rw>8z<4F&6ld`t7k?%(WJcg4UUV9{;MxX)YB{fkbhrYcs@{5* z%kZpMsp`GxbZahd7sBFL9`J-S?q#2HR2c*=i;&l?Bk%O-)ajEg1@o8WTw8vizeTTj zkF1X^^)K6GRQ&<%K}D#@2+NcaRe}pQ9l|lg6@sNR#APEYOZ7+k+iB_Vq@Sck?rCOs z+CNd>Y~C9k{YdoSw4~GIT%-qSB269<%%F7OgLG!Ztz#=soPjq$9KeA*1%4g~e(uT8R#x`Oi}?wz@`aZe zxc3SA8U5_gBYU1C(Ionbhv_ByDt(!BBe~pm`q9~oub(AxB=P*)Z=a_(xqRz$);1{z z3NL}2xF00TMi>+I4qhrHCOmyqj+VkptqWiH{#5de#;mMKGg2TDpM7b;dU`25aqEEt z+Y=1@xs&5+X=oj47(>;F3C}*9UTl4}BEt#uA6+4uK^7B4gM7%pvgeo~ZrL}MK!1`? zHwTAe5~2-6!3WsLD3fO)1h*R&&B^%-mgR){R#iGm-hb$^ZUgI##9b3$qHodD^prk) zG^wkc-@jjw=ZleJBSQ>h%3RjhEm>Cll(z#c?_J(|qTiHwV)p0eb0e*7&(-f4P+9*# z&5ogT-a@~C2)15M(g$qk;FOG~3cx;hz`GajwID$U%wZYPC8M)&%a%lwbP35!@j`~B zKdp*N==0Rcw2w10KS>8H7hc}{TutS?6|vf&fRUwI(Jd;)dUfiq*4BrnyilEANSvRn zE-1JDB>QHcF)y?XE|18a9P{SO^`3!7?w4JS)}L{$CfE$W2XHQwv3}Ef#+r}99!!gNcQ^kO>= zm~=*=qs}8Dci#x2?y+`dQ4zh-lc+~6>yhDG7b{HWN4`+n(!Lg~5%Xqw-tXi~scrD7 zZA^!Xf5R~?5WyW{HpCXTWE_x^{aeYI+xq4tS>OI{+kw;RO_QZ86qozZq1r*oQDaO4 z`^Lod9cW?>-tpTz)Y`o03qDjzKpkHn?%ytNDSDg$3QS__y$X$wNmV3y|k%troqA=r~VqAgDrBPxq5Pa+>R9 zmDk2%AK_)-FH+KtW69!x9Dt=DC%*iI3!QZ){gcehk26lwX@`?vNy+*ua|0B?>G~$~ z{utwmFaXEemsT+H&u}jxCe{zRV5ALXSZ?(Lny{4$eI1>~u@Ev@`dLmvvzLBtdoNaR-{=4u^1t~d04lb)}d1vQ4 zQ3*9!+3~%zbNY~){nJ*irHkhb9|s3Q_sg;5<%LG%Y9H-ZHt%?CPp*1IUYScwes*O= z&MU=LJE#!obLjJ;-ZOio<`%)qZOm`LpHM08gT5SA%u+^x!(P+X8If%JKVRwWYsd*~ zzsF3Wa`wW@t7eaGY$dao&b`<&h5lP_ZqDwW6V-3}vUq>;&iku2%pD_K&l4tjT91$1 zwDOGu{kO+Nq**^-`d~HSi+Gd*9-vc<-dK~$5zqz!p8h569DzZRFXaZ`a(ZWeOUwLs z<`0-&k)2a%j!QoF(eh-K)*~tQno9MbO{?E~Z*5yt>Le7jo5`6r(Wcq@aHy5+^7*oU zrkG(v9@3d4rH>_&?b;}#EmYEZEiG@%nmT8}<%M-1WhY6=c9 z5SRJG=hH)Iudo#e-%UIw^&uq_vS4ryfdlQJKI>dfq$!;6-6||um5I(H(i7h}_gvEW zv8nNcYNOkln>WpRqJOs@!hbD&DzggArQJt=+F;FYz;dF2d%fZ6!vl-cGr?|nrvy5f z{~6@8z-h_guFAg27N{MtBMtTqcw*dOawxu{Ft)y*!TJeI$>Z+|< zYx?!*T}i*`IV!&UTRs0#kYH_`J$rO=lsQGlR#*nU0sV8wz7rg`0It~?TiIU>0kHGI zvY6pD39;3Kq81m;tSD`b88###VaTwU)>blS;;SUIO+qv4g}Pz0X-^4TVMR6pf2lc1 zKeB!;`6U=rjCcUnnqvl*g99R_Q^rap>rEqP#uOEe9$i#4W~%vMZ2ZyK*41SCGT~Oy z*fGWM{mpYKRRgysmo#{FyaeaYHPBJyI%^l#eK@pxw|*2#My`)3Djq$$xM)oCq>T-I zMpkBJ_f0m2lo|bZlT{L_;!$I64p}>NV0^}ytUi_5J zeT-BK->D^LT9Bp;*9jHi`7Cj6E6`Q17?i z=O>ctz5oREB9;RBzXo_GA=)vCcxwrM)_q2EbP^w22Jiu6UN$~tB)N>(qwxqJD5}-g z#LbHe|Eibxr?IBHr!CyYKJ>7|9$GybiRz{3;X@MQss~3cE(9ZK>ufUkn`|;u6AzC4 zSIp!KB&=1ko9uHAcEff4#MJy^?bK(VmF-BveHri#bJy<4H)tApyoV7ZM|ZYj$;^O0 zqt0S4%YE*wx`Giddni=0ip|--qa7cALfaQE`~1qXh4g3t_+?8Hg8~wlVNQAdWBLbC ze{ywQ>!x)t9qQM*wrcECe|$+S~j;S-Ne#a8GURbVn0zxj{tKXG^%aoTPw%yY_Y!E@=&8A z4}rLgE&B!0^x{)H1dSn#y{ML z^vKLUgMG|Jf$nP0^t~sC2XB~O*ndpT&XI-12LBY%)kV~41R>;s^3?26{rb%==>ywZ zzMh>ONQ{Aj{waI+42g9&1{G9{-&R=?5fSiRFo_HbY&J%fR)l+d1@{KaQ20F~nw?;$ z5~-&M8@pxT=m_WnI~a`TH114Rw^8)s;`JpK()hps4H?2UTpQcFia2q-20SorH*IdP zo_q4LKMeHAZ3@fy$8n!OBUTgOEG%ro+PybJX-V_uNeP#}B#ZK!@nx^CGuJMQ)9#IMAFjBDh;lXzZiW zEzcg~jQ(Zey-FeiC;BVgkZaVR@dWV|cDyTJ$C$JJm;9*~1%e;sT#*9&!JvgLMw?-1 z-rg_KIrdBZa9?|c)hO8HCQV3**cJt8V(7lTx;_zGBMnQ!4tab>>1IFljyesJ2$?NG6nG=*<>E$>(W{H3eh7zuyZR6{DKeAQGx+@!?7vE z4g(JO8)jyxdwkhBd7Xf>bxs7sG7a4n(`U%UzSGLn)5=OT;_B|X^y2aeS$Aij)zyZr zGzL!&VrcbjEa}_QH@&nhttyl|vX@U`oKQWvV$&lOVi~{-j@q-nibWbYkh&{s)?cx} zUiH=@;Pji?t=%jW0=UPbRMar`U|zI0IZOxSxw>+{mv-MlnzP)Tt?onfPeIKLIS$6Q z=Rs|kgPsEdLbnB-9qL%y&;>lHu^-Z;{Ky{H=)l8aARLIvN#F1kJ&gvG|V_DqY1hFs>hS|R*GEsFf^gg%?uDN`A9!3R0)fet+3LB8=2 zQFxdnRh#e>1-n^r@E8+J%^Op3WDCxYF!ETn!bfrEn&w^e1`MyOSu}pSb!0|SL@&LI z3(;s2#qQ}z+@g(RXFgJpS9i-2?mmYE%zQH|p=nVA-MB{Gleipc7m`{VYeQX&D_iC_ zjZTa8jU*(@BU&(qd4#BlZ)8F5g=4ZZ{4=P2a$O(myA2Di9|wE+eZ%6*hqpdbC5aQ! z_OUmH=EV*MlL9DWj^Lsmun!@Nh-rrHoCsg3lCt#)Zu&rV?*TiOt$cUMtonv$H>_Gz zsp;YDsn?c2_SEawHf`X1N$*b@ce;3s!(4wDb|lixnuX0!GXTQH% z14sT|omy4r=jHRf=%w-N@HU&((|r6rh>Iqf6s0HeAH<0w zM4INB+=YggA7gYxpO78m5pVt4;O;k~Bos) zZmx@79iJR%HaY78hPY^bRUR7Ong3X*QMryAl>&A|uV@Rjq0vG~RtyT9Qk<5|pNbJ< zgm9GCy;n?nS>zZmw?r$A($`jby42IXaAun>Aexv9$30ax$Zu$UC?}0m)u6%FN%<+w9 z>W4QbYC}T=?P+ah&JVd>MP30R&hbHR0bb@%m7aGCPgqTV_!s>ec42cR6(3C7f$pUJ z_G%1sr@i&liW>j#>p#ySH$Oya@4VBgZf zQ!sTw(x++>=o2EFBqQV)Tbxyt1PtTG=sFgzIx8?OM+*B6t_TP~L{m&3q8*+tj`2h~ zF^~PGT2wt!=i*F%6Ang!ptM6fHFTu)@M_^;q<66wrCvR~f{Wn%Fj6s;Ffw+sX6E#W z1Y~GP&=L&%K`&u+v5)9Re^)08J-WqfyKCw9+I($j(t2MN2<3bnMI{07RfrfDq~QcE zRFlyDWsrBMiui+J>Y^f?;{}sR6T$g_ER3h-TOSEKfG3QK%r@1$2Oem_D6_#mGjIn1 zr4#sY^dBfj*pXSH(YyZ`{@aH7qVk!2OA_5YLU+~mFAV-hqjG=V(_&m|*act)i7{cK zO7zI+7`x{A%-k^#^hzugR*xGnm0uR7^>o&w(!AM=X?iXFTcW9z1B44L*=D>a$^CES!? zIUG~yFUEwZ0+!@|=I!e7j~qHR6CTRAxS{<-%f;85yNM&aU)#P5k?B%ox#Ir`3^f-Dst|PL$b= zk^BVh2b?E^@m>84@H#}%rOd{i6b9uVE8}_i$1%3sYd6{Y zm~^;Vu@0Z(rmCOu6bAOzsa)y*36Dp46?^?x+d~_c7-7oyadsggT*tqBbvpHaj{fQ# zqsxkk2%8fYIx93VrMG`K-*zT*66^=A6}E7fVC!QNEye|Ec!3XbiLpC86FAJnEKF|? z4bKo>ZGSDoGezgD7Ck|5UxUiUEwqOJk@-1-;St)tOPC5BTE(6*CYIPRka{ao=DW&C zGWE>qA-WUE<7AD>*19OUJfNE&{l!JE^`LRC&h(E?q9yn7&GRFI`gk(oB0R{WS2fYz z+0iD?JkOCJIasAZZQbqXh`vwtCsAp z8ur+)7boQB^{IV~gueYOKODA7{(*k6t?esPPM|luy=~W_rUkz(I``b+qs=QxZxSij zZdfZM;ImVVQc}HpXH&B02&quIXYLR zK2GE&JUDUgWAwL|pqg6&$t`+>K?r)(F6YW%EdgQ0Tam1oK6rB;t; z>bebzb7A%Kt&iBV&kFQt>G=R!CPQ1Q$!=2z#v6xpj_P1>nEfq@g`n^_c#Z`hQ;}cq zr4xJh?pByL@|R_(C_6`sSk)sTD8$dz_dNY{ zBdBf3Rgym@>>2N*hf^%|>2IYDOOChRuw`lkZ1w7Cw&m)={tvWHt%>M%SX*%-drC%F z&kTOrTcFMMUn)R#PTe3ko&kG@Sms!_!4Q%hrcfXl9b^MaK6o$-q;d8W6r)(G;2$j5 zrH2N>nNa_9sJ5NycPl?1oA~JZ^pW(Vb3fEIx%)WRIqP(ub+ubJT}?{ec`SSC)(1|! zQ8ClaOC09Bp#IG$FI{gPNq%$1%*+6@A#K>|bM)P9+q_i~WOJ0azRIVqvgq4Qqth%V zb7a}R<7-!K+lKLnK%uR|J;0^-BURC|d&tq)o>=WA8tbAl#X(wy>sWoQ!)}`~RaGox zseN?%qU4E3Jwvthf6i);>5Z}aYCYWre}#Gr(WT}-IuAGE?3&s3Tvc3OH&36%f`{5) z$WIkxcz^n6tex03?9KDu;90s5HDnRBuQpMLjpy_=Ngo(>ge>sT zu{woJh1i2Jptqt6;0#kBvWFPop*)e3zSLiEsA1%Y${zBlwwXf1io<+;wz-DouYd5d z{qJ}m@&^;ki1O~G``x?DJ9O|UFOBmBeO|$gC)O{DKPCm##OD*Wxt@Vg*Qj~UJwB|j z_38BSkIr0pd4F~pcWji3b(dLBKn!t@>}anpZZ7GyX5mrpbeKL>r%{VqjHsxiWgypA zAQ#MGVm2lvLN@NmYColZF@%QR!1uB~=j$EF z58`;yU7eQ}4*jlirdCr(+&ZzGbch}v1s0QWnGwDUK3>ZC2QLl}n;+&k!p|40Dy=D` z3M5J7|7^b%l_;F_chftIyd0c)*Zd9_eo>!VA71bRv3w$2QpFC!A4>7h48i&fF-Lz^ zEde=4I@l7i7n$~I5&~Eh8ktgO;w&B3!-gMtyV!O#)LrFPEs2_&mpP>V2O|;1G?BCHwKV9$gXk}T`pE= z^oo%IK2)c3EeT8_g_d~eaQ*IG;vF2t_Z;l+6%(iV%`3?>KPnsm`36DRLVhIgXAO!7 zX%6Y{mgMFy#)Yc=hWYzh-|&s2-%WIb!2?OOo{9Sphq>#y4GHdoEM2%J3QqG0=xz-2 zb7hK_#u&;#Hhj9_1CgJxk5budXTk;>97CK~rf z7SBmzU+vd#L`gkyi6<-dam#7;wyJk4dk-RqAXRWq-@+V+8{!X8-QiG@mU0qWgL7cH+WYF*oBP#?3Hn6UZE z^hj>Pyq1TXmQES5zTb~r%Xp6n7hQk{=kF^9TUV@|JSypONkOIa+2;mcB`-e!?h5`2 z81k0^Lzpvg``imDKLL-PKpn6BCE`dDrv32GC zRLl8}NJ%JKH(_Ah6msxquha`Ijr*P^ri!%0v_U8HLLaE49b1NTLeD7EtT7Kdky}x; zgdZk$;CvqI)LwDv1w+F^Y95kMO$!qKUEU3u83;Ln!ci9k7a%xMlT*(ZI@cV9Zwv zhv3AwxigN?n`HOJkrV#9`i4jB8t4uE0&EZIHLk9zZ%l}3hs14gq7*#%lMx0WeRbGvVwDmL;gaV{$qas#;*Y&1 z=e8Hcl=h4Xjnf5<+*2_!Fej%vrzSTv*4-;0Xw>fBV|;US2IUOO4U6&g_7nTWbT5nP z9@qY+cggQ#E6inEw|w5cY*gw3v)-rpKXv611v_?plV3J6Wo|so+j)ncr`|!%SF7uHXzRx1#U}Fk$)&}k z-2%&^#>`EOc`2+VY$E!5aG!7H)c92T91LDff1Q!-8!TLn&_W3H(?SU4BRUp`HSTjC z6pm95olb%+ECqQ?C{LGYCE0?)HRF|A3h~IZa72llP9IRVpn8%E@o;;{S3Pf5V4xIp za75>9a|Au zO(rke{$9K(e?C1{=oO!-8cwcEv}`{<=<#)H%cdn}2DIhQnlyRo(6RJZhCXmWePV?r zv-SxV&KeT zr82?pA!7*&Dxox~d-Lk8YjXw$?a4_zo#>J45s+Hwtatz2t7v$Uht5CP6q4Sre4^XZ z2bWhAZCKauyskmznlR&&W-~WoVe>;xOE=SJCU^!q`$dVOK1xujwHf?JMTxQ{Oo*!( z-s>?eUH0^$1O45CjH}7Z+hy!P9u>%w;?$GLgEfOBiLI^%mYF4VsU4V4I%X2M2t-j4 zdRe{O4CV3{Uhs$_)H!KLU}&(fA2)v`mWJJ%*KAqSU7uj_)nAaShC#z>^o`E^Qykx( z8SEaY*2jVnMh#ckXYROh{2C|_S>^C>L`IKaYz0HbKr9NGE%RRk|LnQ0+VUtCPd{en-b+ASOVhJ{sEcjnrOC&J(z81dcTVCt}Xj|rseW^NhQTK zK7kKqM!9}j`)piwE^|AZnFdz@*rO^A8zO->tYwY@Z+VJUqDx72AZlJ3+)yeU_yx)d zmGm@28k}L5g9-CT{Q~0ijiF}4p~v%lDnge|h$@YkM8BRnU}A7+M(@7q376mP6WG@< z@57Lxzl|v!z>5jS$lNG@ziEr(LW&|iO~DaGBYX7vEHSIm5*1sVo+~bVFfDd)jAuy7 zUQ5BNaX2163wRa9zS4YGX}}D#iNuu}DjqDab%vhGy*OkXkqhBq% zKu%6cFMFJi#4;7*xylK6V0D3%vK)O?NpO-YbcIk+v6Q~-462+Gy7g!}@=o^P)vNjr zjE|0v%Biv#B7?O70i*VokByvmq_kVM#xu%4Gc-RZbZE%Fi}RuK5XTbDHD^*`Xx^2r`PrP6PO=M-<|VD&-`BNb~U^=DN8+vZl0NYf$Ut7)9+yw z2t%CGAeIjSSy*(n`?F2uQq3)mX?Cr}I+tPqvJ`EFA%%&hBa`zt6waDiR}z~P;jIsy zdEr>fpmpV$Mcos7jZDek+#?{>-15)>_b@jP|Ik@49?I;$x!h93=Oh*v*LVkiLmOsp z?w2&apHEQ!e-0fAF%>12lnn9-xmkB{N6MxXk)?k6!2I729}b0XD(Zul2-P5i)C=oU zH-b#y;|3jS=&vmt!zma_wfe*O)on*=^NYHr_v#tz;%Zz9i?;cZ^JMFmj0daU$d(lY zHtF~23Uc}B&cPi=pIW#&DSb$0-@@3QFxl}_u5S6+|gs{E6Y#JuI84& zz$NmY2XWvH;2q~8!s*W{HTs<7Z3^^J4)tzkBg+#k8gbh{P^(Kmkvu!!)5SlaW@EQ4NjWPyKmKUgjTbM~ zJC~%!4GGl;=l`-lHZUXBE2L@dFPrMQ;&B0beag`T2O#gmIGMOsY=SkUFn3-W^9M!% zS5~^fENCMStlyTFNhXZ{_~{_9;#{h=&MqGD$KsP;N)GULjW-m8)6%whi#ZHNxB?pj zgTfONvvk}}A49(|arYdpp6W~KdwE_uf0fD{=c%6e5O480gqV)AOxPR~9^Uf4CLA0R z4^JMwWp-)5)Rpwb4jSa^k{MC@>s;R;kbt|oZFm#?b{_rJ-DT{xCH>1QSJ4Yo^@KRD z=vyQtZ5lT`)U$h8^N8Vpm=j$EA_|jWGYG9dAh&ekE84#&HAvw&~LX1LZr$~m&kW7UrvkH#f}<& zXvwT;S>C?xB|bg-Kiu{l-LbdVM6!i=yfw9OSX7W$NZox%v}=s(+R;<3m!4esyYl(mnQ#>QC$GA@{^%u~e}B%1ymWpjJ$#e? zW=?iTtccnKSglyHfh3al^<>l3?_Nio(Eb(!4}&F~7zPX`d@vzT5VD}LN!?ckCb$F= ztiqCf0SCXb8Fk=q79E%|n;7LQE;8}yks7VK*s}3pm{&u5O^_sW;FZwZa*_-ScON3i)Vh&qwX%A?LP+T-BNl*{Te+X$jJZc>LvQo2}VIt>;(gvG(XJWoZzZLV=?E$LOw<2 zdXTyQy=C^qS)6J~9kR?0Aw+gll$HSp>hcxq!ugDFji;)}vSwF+*VNb{u^GN9wVN(4 z&?mtySQW}8ioTv(lcq#1$Z&S`$o@V%`CPIr<}!B>^9vVAOb`Yh_bf|_gkzXM%;1pd zaMkFKdbGfJmD&K~*45TO`53JaI&vX@ z-O&Nj5hXq`8l9*O%E|PZ@f+Q~XUno5$bdJe^&B3e7kj}DGiuSiqi^3@wUPLle0SJoF)+H|J+0(4f(WCG^YyfmcJslNh> zF!B(47vT&VR+L3I2EY*Q1KuTn+h)zpvtBz;tDl}EW@cochTOm4sXk&ypF?_w!U z`X#1HuMX0x`vvAuT!S?H+X2^!}rx;))V;LkwwYeFk<*(qBC5 z8feVEmJ_|(3=rjtq$7)7PRVI3vlJ93S(4K|%>#Rm=8p?t&%l86ENLHL08hn%K6Z@4 zVJRwVxs&pF7!mp#s)wba7@%Z>Q0+5njio&`G@GP3_sTYycbQ>NnSi+DEUK)Ja)VsW40cIwcs4HU9+H?8TVXzJXQ08BqaZ!V-3c`qhj3=Q#;aps zXCt+Io)usyUUS1|&Qs$uhG>F>puiwv4Wty?5)Xcn#vd zw5AH?UmI~6tIpe)>co~eDTNPCw!Ze+zvzLV>3=`{fsFi_xYB=Tc3(pOu`)ZgU@=MD zl*f;zJ7FmOU&QTaGLE>AK>F`xs|SpwD^WvI+PdU{GXzztnfg=vvC-`MU8~lgiEz-GVF9DOyXjo&MEF!vxZn-&CS?21?`u2dJp!u zKx~Xq5f*?AvpGYZ`vg$_fthwfOnKUc!{vUN4zq>CYpd4(UqbhaD9<2WaN3xL=`9BL z{sREdPktbyejzUOx9pxv9$Qvhm^-d%KvT~Z1Ip;8x|F`vMf?bQ{kvb98e+Y=#ill| zYFnE5geP(Tg-igDL+H=*S5=SN*+8w|962_2;KHXHN$_vhnzrI(=p#eD2>SgQ@Giks zwa{09Nu>Cs1RfhgEp`XcF;Y09j^4^vlPhBnP}UKs<5-~wm8JMI=i54(?oaJocwp*W zeW1qGBjuHpq%%oDK5j`-6~Fpa7ojHRK0W<`#$lUQ8TwYo3NE0mAo{@jJ6xP6JhX0& z(f1|ZdDQHGro5O^RAaqv%X4vVDvU5pH{JT|TRU-Rd|_Mii^;QRc?A3M<64RJmvPGm zfsEZC*SrjRa$?ns&If8rbxOFJ&9aA6;5$tVVwDR1g@Y_GU~Q5IBc(a+=0sRPYysnE z)r(NFpoVwWi>|IB)QugJc24c{P`xE>-KICbo6?|)^BwM5?9UO`u>;pm@6&r~--pLe zid{e~=Z9Ikn|=62)Ns^C;1!2qSDbMKh7F?i2Y)YpRQjw|81lw#7~3 zCG>UC$|ZBKD!DA7#po@xZ{fIDOh~Dcx76>5h{!N$&OaaS9}2uqhJMp$GOui8Sbn6y z`bM|q9Tk`k8?*uzF$g;3)6Wcv2_@pA@w;|kes%r^=f@X%2O6QAf}$$G&$%W3px+nA zXE#Od^O+rF3}0T=-dj)^F(oBC3#yK5lk)#RzTN|_ z>8tx6=YBHSBMCc!EJ6q?kU$a$5cb}C@4cshAc_l6+}2&Ib#Lox)z(^DJMFHuyL~!s zpSHF>T~_(|N& zTtPViJ1}4}IfLfre-?W%Me~o0e=lfQFq7^i%n`A#mI>Yc75jXkCUSSM@sAX3B%I`l ze6e)3#J%1PYNSZz{UR?f=6g&aUXaJv+QR%nIb)Z-DOY1TEcGA!JTN zI^9%m80$|SoTS4Yl>d48ACg+?Rc&rFD;#9(C{JcRDRGdo44#b1ED_Eriv2!8SA+OG zn_#`T4)r=YM(M7&Y-^Auq=A2c!5;N+*t^8))Tk zWp4gpg1B_ef>M(HmeIwbm85fIKIllz^svF$|67GcAuZ$oO#O8G9l=x!n_gx=tTM#- ze>*3iFWl-+?nKtALU*zMDgWT>!EO$grTnwxDxn~lg*ErttMD8Vx(V$)dqSaCaqN5F zV0%ye1N!ZJ2Wvl>*9H{m9}jieULWCzCqPW$s3xmt>TnT;gTU9?oXtX4$>fK#EYxlc zAH+s~5{WE?AivV)f%g&wo7{}*jTQk{qj8wQwga0)oBaNNv}=HdVStO$`(dpmSm}pj z#@tT5STS?IOx(#AW8%H6ghD7pmRdGz=Bu>#;0O2~^;NyBa(A#U65l}QnQ00!xYfPE zjSm1-&-9SlOdqTiEF%yLog|*7rN@9(SX;7Z-X?qr3l{b*&@0qD&}(JsKz8Ho4wNnw z(-@cfbh!yB2D}5#1}=rk6tRk><2>lUdg7%>TcKqvKRVJ1D$QCKE@RC(^5bS3zGa-7 zI>?^OSn9%(dO6=;HnBIb)KzNp(-$IFfx?A3c1ND!Dz(0TSp{5=_q?8jKAns@Z3>-d zphoy46Fyvk)A90Rj$zgW({L$6pu4sR%Uc7d}$1D1S7 zKY=a$jWZhm<0m>VXtb0?=!qQ~N&j#c+&uRrk#!uqYiAL5S6zz4V6Y8#azK$@Xx7Zq zyV!%UwDk?7yq4fac@4_;hun7Y^_1;MMOb=qgRzwe=6!>oBKcKU3FW_>1E*@%F6Y3d z612<=u#@NfZ8E^KW~SP7{;(uq44>|lFhop-`Ev5$6E{)DgXXltw}yY`%l-2{?9O1= zdp!}Seme!NzhG%~`OPP0P^mh+?n=BIEl4j2jp#^I68`FVIB5tmHG7dvV!X$?iSJOO z*GcfH)P#d^_6FLkbVk6h8v*W2)uGhJ6z-(qY!8rPyeF0GeblKU53zgf9f9~>dLS=s zVRm+*AxSEaP=utq^R*%i=jE??0J`3nDND{58&X(4QNfxBMP-ncKUwM@Lt2t=B!1kQ z=og#|uj>^x0oF@BH!*sAc~1O4+phZpw!v0>GKq=6R@6O2AT`zPhsyGw@;x+zgNtFX z8|&dlCUCtwI&UdctGb$cA)%oXkhBP=#|CX^~3a zaT|F~q+Bkt)VmOVDq;AC zNmG&oijzIe+2f^+p-^DsyoR~^UBC);_t3m;aa(&HBoLMVgbB@9R6mQV$zU#-$~Dx& z%2ecnJDBeh((vqthSV&}C$p?_12Ae>kjRx3Y`oC9kfu&uZBcBsrz~C(l@w;Bs z{KEQSj!(UuX=M}Ohk-Ow&=+o~gX4t@CFB-=8bfbD0wBy~Mi{|^nvP35`ux(m<5NRp zBNh4@g1^$?iYBHTM$j`~c9TM$qI4x*1zlm+4kGtq?gh|bqNYG)QdXuRUd2o+D-;tJ zmYyL*+Ci{0`!@3S4w52+7i*7^Qr~nG^F%mZhUlwY1k7|=vRJ}_fX@Uhn=b&qpl6Uw z9|E*x+NGV3MI##QkU8`;@S(?lVw~;@VYUN85#j&-8K~w9h>CwfnA$>^#-@gg!yNft zmiYnxkwgbKFC)S&-;Pj6*<}X#M=}=M$itl6820W-DcQvZ@fn<@3z40C*8EgWsLjM_$da=A9H8l$$$)~?K}_4ARtxb&%6 zb~c{CRxIX7Ntaq%C{Zk0w7GNPc?qAfk-QgB{E%v0DXDX+0b|u|8D5wi=yMrn5=}X@ z4|KDmZXBVy&lpZr5;YAbn*?U|9X@vdTx%C9cyPA0Ta?zNG?`4_zp_N=MuyL{HDP6!|N27YCb`<9PQQun%7g2cC zv_XjomDn#AUr#2t5y}`A%QwV^0ml@TUMa~Q&B-3%{hl6NjxDp`&wSmwEoc83Tw{Rj zsUW+8+GT|3`(L?X(1dNuR3I^)?f$Q{nTp8!(9h2FlJAzwHpx5!?31~vWp#8x+n4CF z%EQ*1{LWOyc9$@AAm)8FEo7)I6IB?D^{jKW>tT=#*Fd8*4+1usc&36{8)IbR-~&>7 zC|Ay#buJXa_RdT*nZlq5?{Er?nYLYGSqKq_11w)eSXsGa$Q?H{t<3Hs9>j*~BNdB; z9vx9L+i(~eL*_L{DTS+r3;TdCG9dRgf*hukg}8jCxRstD!d3J?Hx!(4K}5|DQ9T@x z2+E;Gfl!;B7*vw0iOMiUe4E8|NZ&q*(obEVCgyUThYEL>6!@rM9mfJ0&%&MaYPxQl zi{rVfj7RwnXJWeTZJIBl(+1-#;al3Wpccq<?~}QE-y8d z#HHGK%Y9m#i&$fp1%bW>#;A>Vj)Y-jE%iqs$aXMqL2qwN@^sUR-ri(?pR3OPJddXD zpmg8|3=Xbtdt}PinJDy+Gx%EA&72SOPQK>uW8z7smhl{IUzk3J86#{tQ^vsP`!De^ zG%;YQmzmn(^_R#aaxa;S%V03m-r7xLlvU=lY*(lEdbyuIM#3k^kI4JvE6Af^S$B7e zpU<i4tQQm-BHKL9T(IvpN9c^E>FUXZi`5lULh*o@W@IR#cKdnn; zvN=#t_Wg&*Y+q&0;@tdiQnMG6TPVQ?R4n^>E6cp)n~L>p+iI)4K;I~$lDB+yjeMQl zS05wg6A#)hlFxS}_V**Ny78_~u=HhD<(#E^`&Kj^Ug|GVN1|&1u?AmTOERS-`f(Jq zR7We9h{qnxf+7Ah0XuVhrXaGZs+n6LQmYLbG+6aH;DgzzTFA7wH|HvIdOw-+3w{$b zQzDP@Rp|mHI*qT$E}vJIm=NP?&b5*H6N;Sb@yqd|u!yj-m_(^O%16!j2o#2E;e9zy zbxCmscXO_VZIH|2g+s3-W_A`26Mx01!}Wfu5<5{$a11$6qOJ|sCVDF2Xt4QYVZ(@8 zDhmxOhWAAJsQi_7!dP_-T3R1i8y1@6uI70x=xiMw?WX(+YnsELJAIZB2Adgd<~$K& z&77%K*Z&bq*aZKBMlBsm@H@-+dIkB`6HPe{QhB5zGCL@Ku*e`zZC;mOF82m_>O%Y+ z7?!p|6F|Kctqp|}bSx#X9T1s2LH_5|AHE?K(Ris=8{oR8ag#nKWi<{dz-*i@nj=w| zP&+s{-TKHeqHwOpeFM31+iZO4hYNhEMet_RXd6f<&&>Eb^ zAbF?nXYcCyYL&00rJZdUpQxFMIT9SHS1Nf?jNGrDyios&w~c`3VUb{&av}PtN?9vN zVC=PUzx#diW(!-Ep2u|;vdzh-rh@_l1-9%hpC3L9cYY8|J13zP|C8xykd--mZT1el z_c54jjf46K4sYXTD4s9Uy0BT46QY# zO9Ojacm_#hVOy=O*}rcYLXWziBX7I4?Dw|2x&R(`@W)_YX;Y>$RTmPX%Z!YLRvxb{ zD71WS9kMxuY!Bc0YWZxk-N0x_`^uRWx{QK|Fii!ri>iFO`*Hy5u_a}Xk;}-5FWqi) zW*q$)7SS@p2J(7*N`GdDAuyWHad7kxlkkyt`(%|qdL>e>`O3QS#sc!Iz7q*W=Uy*8 z{W{qcnVMJ>U(lYkyT0xHm5J-YCIpht-Z8gi9e}xYxQGsS2X_<^l49WYIU;EL;fq7))9{UUhZQ4 zapuU%2%hVnw8{QUYkP9iqXL5SDqqP9?a#|@&3km!*3RBT(^NYi`QlJ zoQkmuP(Ne@nMMrD1TCDJG8zttv6ohZQ9&U`#r~{CUnud-KSEA+Z+K>?D!cF6&i50O z#-9DHzOr_L9KF%{{7WkbSz^}s`gb>!l_H0~VH3>eVs?{cU6e8?NRwT2Y;|!jGRsbR zkaw@Axi%rQpB3U8-=0}L{My@OSww`JS87vU#ztsNO}$$w_aPs@u;axyFT5iO4-8r>;`tn7>=-$X>Ss~70?V)^nIg7AethHG-?gSU zq=%%1s#Kv(SsC5gp-BnBO_#gbCte`asCeSooL%~;myA1$%$fxkC#rZ zb%+Y94^t86zd)Jyf4Kha&6uE#tfAG7Zz{+S|FhCktu0?#lIZ5?=2x*OJIJ3od*X}O z@cb*QY6A$y598-+Y^8eg;!}lDTA`3dJCSjbv&KSKgA_HL+zn@9W9xOS)CuBP)jcTd41JD zU9KuAEHpH%J~exNW8UK9A6{4*r;_WIxQ~#x-I4b$zlcFQ?VDe&WsRE4gQs6nu1hJ} zufHpGP#_M6e5x%q73mXPg|1#fTw$WT6`d5P?IQ1f_UW(WAG(BaH!Jh#SrXR3FocjRe?Be};BwP}5m_cN__AKwEM0=?BMv)^0vvUZ!n_$1zA^Tvse zU;xlzNR9de?cx3`BSQW+l;9`;ypt~9;hhY)R2p7Ut1NnxZB#buaLw0O?G~c<`;y`?8A{7QHdKy+TUKg?!qSl_D+@_4tAU%3+^fZ%Bw4) znCtb-uu$?5^56?$(TM-}dtEA(0F z@_1Clv*qd&BHy2R)Lx9d(>Eb^N>{U|;W-HJ!d=YN8BV~zDKlUI07yh={>&F-3oZ}T zz$`F#Ukn%ozruRg6YfIQr9S!6`qg6*UK6MQ`R=Z(U)j-6FEqCmxm^7Cm28FdZ+H~P zkGo4Uklo|2{_;v;Y&!GTz+~%4|0F-}tER~*lyrA<0&=TE%X|X63etmfm9C^2dISr z=gKID8p9U+`7rNe_fla1I0E4?%8n=+ocP9dK)+{hCb!M zV6(9LINImg9V^K*`W6lhQ1+p?PYd2PMm_~%nEVENVZLD9zV|fw;J3W)Ehgccr>P0tRK~=htnd5INj;V46 z?_inZV#edvS#ma^<~wrtRKs9%mMTLR5~?eVkDsVZPYBhJ-wdno-ufY{l-Uq*Wy{7$ zkDSa!&i*6yTaGViOmE7o{?~S)2376%XMVTs;|qPS4U%w3c09X3F*wHE!JZosF69@+ zP4xFM-YzbE`|7e+o9is zCxh}_-0RYbbK?iMBfe{-IdcCLY5>3^ZX16Yk%6ccU5h7eMYd{7vsGuJ#kBSN@2{p zlkc%cpGhyO&FY+3lGJ+s@JfE1<&wU~KGuXaE}B5aUgGcv;Y&jg{5CpU8y%CnJQIUE zM!@0l6neREIP26j90zb7!+dMDZ}vwEEo%c^rNAw~6!Sp5QWXfT3(mjBzflxS(Ui!{ z2wbB<=HCKG^i8UpPC)T632Q90`*(fplj83bSg@#FP*62d6XWCMHypLBy)4u}OSo`U zQ&13HN&Z1Pm!?dwU1}u^+`8gGePqnWF_d-saQ9G_WrDcnBduJ&<%aOig5_<@2S1bl zCWqsv%A~xgvb~(al11Sm@iC3NBbOGZ){Lyv9XnOIr6f-wB)vaQsr%`}tuC?5>4CS_ zE(+Dw9l8AYjgp%EgKHfcgSU|{45&RbP(%<~^TI`Inwt;Jer&;IO;J%i=Uc2KUSb)) z=Imn3#PIq*axpIA0OGJ1LJ;rpk1V)P9j`e$6jERG_E&|Dyue_oBb@uq|GDHsYn-1@ zvc!3i{MfCod3#krL_a6`-r==QqKL#8xm*7XRH71>+y6S$_6Vyz1QEZSrBFX!e zf0G|&FSyO085u|fE1n;3X-zL|&QN7VD}%BvJagkK%61oC-g@%piKAN^TLXeq)QXC( z1vZ}Qr7NCk81HV~edf$dz2&@#n$>IK)q3XZL9r@t|0oz3>mhB(e=S8}T=MdTou|p& z!^)6|hK!bo;J~mNZqz0(o-@3!rb$T6O7!Jd&VaA!SyL&pq(5j1ZX%#kJxQ6<4VeoRe5ob0IZGF1k2 zyv=h8RXu}|;LF@LNfW2`^KByU9lf!kd9)=fG#&G#Hly!QS44gMcvt+QuH@P@?!vV5 zUtUYs#I)vD#fPda1+0dy#~vH&TtBvYX?df9wYpug@qVwoG{ca{ipVbSx$@|4^0}S$ zktvhe9nm4tP!%}BeZ|4!32!Vz78?wG-6>7e;%5g`HCNLsx{8OpbJ`laqZ|*eeRTVV z-K(<`6EemMvMs+l<>P@ewyL@_3}Nt`Tqc=l?$6q6mIw7xvso`jlPP1spE!TQSQRD= z{DoOYh9P3Kp0O^{P-li<eu+$trGc8cdM9ZlAZLuW!0%TTKa9 z#65EGCuIAaA0gm31oWkjz z?2o&5{u0U%+HciN>s(jX7ZG1Rct6ZZ5EemRRpjU2FOEdS8}e?CQkC>Q9*FI zldq7NoA zS#W|=hW3Q@N#jdSJy`81%1DTg^*;*=V0$yHi5IC8Y_!l=7uv{lEkx-?hp^G)4D0c% zCA(XaQa!u`@N6>IoUnMEpI5j}sA^lgB4&C~)&itI7}XFH*Blui1oo6D(*46#UXiZ0 z=7PU}7zwP6dc&5kHZV#w{vA z(r;0to-LWIc&Gitt(Xr;9C#0s?EvR%I`7__+&@+?P+}D2nmeis{Ya*q>SnvE; zI9(;_N0FJET9y6@wL>xeCC>KbrxNmUt6zxRBjiDj{Kj`jY+O;d71{sbJHl2S5M4c- z&|AWF9rc1s7^#>dNahqg4+*ClQziyO;@-fV5(daSAh?Xe35ZVSg!zXTYW#J3AmZbK zGqR%P-itfBj|xuhLgwUJ*QWRFnBuTpy}zbV|KMi`^BnJpK);x>kDhM&hV$Jf+nLi@ z93wKdMbWLL&X@jHH zD<(I=e9zgwtyU;(|1^L7JIL&(iOx1d)6DYD#tnXMiWYq}Fh`wJL&D&g2Rh4ar(&+Ho?LSL*Uf8xuB?U2S@{vPrJtH!D_>Q1&; zS;;*e-9}wShUh{=U~Z_lI7DfqtVq|4#D5L&?1Yz3W>T!ea6ahRJg;)MSp{ScoqhV zYh$ZKWk5LGXhMKqg9*LBqJQVS5q=N-pw;VeGCWo!22YmW41vmXZ@#B(4fpVQ`} zsgHqs_4u!d1+*SID(?Q&0V!;yg3xK=`-WkQ+HC!*^%vb1OwlRtDB5jRyM~x~`$uG|ITex2El# z$I4(K0IC7s|H`}$dg8v+|LXa$a#$nKhtlqUN#Z)zN|}+jHBM3z=kz$KCx1k}c4>g1 zDtTdax?xDgOTE}XQ5r3iNF17~#Rc7-3n?w~y!0okdc*q)+#F{5JqdX)m)yiz6x5=Q zT$bJGJ8^e#O6eDqR;<{%#=&V&^caXqz5*Ov%sfS%TYm`Gv}14#n&Vrs!6Q_5RpbBv zufWBJT0$c>#Y-yVxnYe7OBxObswMFykq>dc+STRj;OGI5-=Bu<#q z8}8w-1C36o_mqqsfo?;nwHK#mw7>$-~?&XsNP>`TT?0zE4_0l~H9wQKRK9 zj>G<&;k=R=aLQj`XA#_5isvTSAQiwEBLtvKmorowh0bkSb83dw6q4}361nlZ3C3UL zxqNX|o?7V@z=wXT!v?#^Du3^)?Hi>rW%=UPrH zgXH|7&MRD)RW!ZnkItCLg5>H54w_og(k$1JGk*<8Gm?A%H8Yf-L!L6Ym!ul8ahIWB z6i{bXO%qR46B{f{r3^aR;VK6nT}xqu5|YPI*st536I1YEckB{%oglPNzraPsm-$5* z@^yT7w+-By?@)x}vxBv*1HA{L{e znjbi6>orXdJIUvdJ3DRLhZ^msrw@!2IdDh4ps=HB-#Akxv>Zs*SRua!gM+a`&u7+@)rX7I!yO8MF>AdFV$uwQ@2h*yC-o=j(_>`S zj-0R%H*KLb)({zb9O+Z}LDtW)0n?fVE^^j|vB_{)$cdX2=Y8i-I z#0qduI4#Lai;wkwotB-|PTVq!rgkajWT!%vvL=;>=4?&Swnkv-|5Ah+Xq#68s?~O# zhbB@aKEEL|B)Fv@zoj%f!I1KC`$@iTAfyE@p&0jeU5Ab$hqTdk0VAh1RT&AXH=Uf5 znv%t;uvm#&6NmK4u7Nf$>2+DHulDz^N>mj_kD}Jv@4+4VT6-9s`7Mj2Jzqih4e*M8K37oC1C!&HfiZVb<~LobIqwwg z7E@UV`$-5C#cpHl4NBQiQ&;Ui`~?5v7KCuE}^T#YgY;4fkicHsta4I*HJ` zX+fom?-;<>*$RXF+<6x1lP;c8L%;}=O|IuI3Th6GY6)G*=JJqYMsTg z>~6L_YZ~UsU=jx3n}byYB*G?>ahC+Nf!>EFOkDEJc&4Y@dOJB_@&`o`!GR)N&9;vW z^wBAjUH!OZ_n0~P?Qo1v@9gTvVlk~NRHeTm@f+5WI*|ht)$n{Q;~cqUgU6NGpnya- zZ-Ikz%-~A|SsbK_7KX(jhJ!K=&hZ{amux(wVp~S}1I3*{5voF+Xc^f{4&$;E?k0MV z#fKU-5593^8TYp-$&FRVd~Sk4&H0uxPF64#K~Q;>DlB2Mm;SMl_V7tpXBMAaG*M9g z>&+iC^6OoR2%XT@-rA;U>EY%DU5y*yIWgP>p5Q0h-bh^@dF;c)B3^}r%jocJi!KoJ z#z*BmTPx?=D7Gdpjd}3%V=g(x%Rk>aCH9FFcu6?6wmGQQwYFe?eh{5NF9+EO6XWdI`3X}<6AX{F#yZ!{zQwF(wa?#pOu^6*1J86M z9XCDjEFGp0+LNFo7vDX?tXFtTocxs%F5CdwwZSv9^w@N*oxrJF!eN%~Ie6g7+CpK$ zJKv*-EzDnn8!Ll7-37Mj>(IKHmj=4e^o$QX$~`nT7VHhRjT3`c1{a{X*T2H}firKc zFX8N)*mNsA%Q)6X?V(dvmgA}%4^}}J4PVpi2kjdC00lTb|K*eW$=_#x|Cl@cuYg~Z z%sHG|DHjp8-nq{l+J6x-_q}@f%8uWC!+vT<&L8|3>%+Z6d*Jo}_Y(~_P1+%i*o6I4w7w!;&J+POlAf?h7pcfknPw_%# zrqP1M{4d*K(Tz!wIn=1~XFruEk6pR<$i5|& zU6#_Jjx|r-y7t^B%-c;79=42Fx3<>>{NBi5TfUd%>NXF4TSSP`tJ1?&V8gOpThpM6 z9rBQ_Ufi1)v-8Py9;8RhtrbJXVa}F=3i1%SalVu4 zQkr2Ro(DMfFoZOQRjbH>K)vMJhzj(*qh70UWs@r#Ya^$XuwFVJf+E9(_SWVWnm#K# z*uV_jCvIx}y8A7Jv1?#P-v@i1!Va66Yz@Y(@L2kVDD zK%@AE+SflmkvH}Z*)ighl)JgDx=?K|u>ncLUL-TGEMi6IMCRt}H|?K%ePIrYKYFm`^C%NKt9Y&c+3q39W&p!YGc@8#5t=40B)_W)6Dt+)(?ex)LOQ z>RFImF}t6g!iqNDH&2%s5(qCECNA?41~Q5tGC52Uz{o8wn`rz~@W;3Uo)mMb_++Or zKFjwhCTye(Yb$Mth)WQ%&X(pvcl&<1VCKijGOoWvt%OT#sEZBqI;J+~*td9c2wO?Y z+KERNW_o)Nf1#&H-C%joj-pN*5(;*#bg0> zu0fU?yi{GTfe&|^ZOwWV)P zfe}fbhD$vHomLR@r~;{2jtPO1e+*0nI z$*X@ya2x?#wyeMn=vVYTXdzJWBT41mtTT;P7BW$!HLE2t#>T^kj|5@F()D2u!EmpS zm3PbyiU-YRo!KrRE6^ex*L07!pq;;?0+Dp(9*Y2!Mp_Eh6LJ-*Ye{Zz`HE zjI?%+9?3}SuU(tIm56`wsyJ2@X@eLqPfucQ)I*Ni3%C!Mzg^eJKrALE9XxFEPs(8s zSVGv{WjQhcZ}TzyP?BQp4HiIxife*)Z5IxmeH87l z=zXv@E4jqOVAlwbCh-jW*r}1rTQ(}=G5-wn-e%>#A%p<~vO=LYvbfNu0HsXX>Kni2_J?0yrm+>3|%maH# zAxdfEfj)*aGwY$ff#pcDXc+m73u~4hZ)_90g zECs=_fuZo6Uh>1&cUpGKh0$psD|2?YMIF=$*>rVd;u0RUdxpOQJLAC-x@ZNy!Sds# zHWjASwh#W+3_o?1N~#nMV48(_r@Gow{|pC9bH0JRGi!EkwKdzCeSAaw;LYVh;R()e z?ipE;x%}A1a5%?pWlRrKPF!RDM3X`FyxePyyc+$y!vWTA7n*4JcQ4u;#9wqn8eC6t)5QW9Wp=k6O zIzo7catebFkO#zvv56<3XJ($B80gs)-esXv?WMHvpO5G-$%?Axg4uSGO zm<^Hg3;E7xiw6$w`dh>2CI$rTd9roj_0P`i(R(K3?cF(I>B6m&@=)f^(=VPa&tjY( z86aA^zQ0yXZC(G(0i_i^h8@{hk}d637htb5eY>d=y7jjBiG zIh-1(Fp)#}4@p)|c8wCMOv-!u;DO&RPo8C3c=`RXe;bs`qSCt43eT;XdNP9a8NCkV z4+8@Gh{en{7p14cSSuNzXvX%Pp0#2<1@?tAG4w4s5XV#$L#bvG*|_)zWSB}LDp-t< z19Nh~!&gQRVB%#x#n*n_x_RdP%^Y|{wL6lm{9yHDUHj#)Paew3TT@x1cjd)CaejA2 z337)WtI!(*9sj;bKC@_SLtm65m+MgFlr4SMj_)N_roZ{x?W>Ddzxw=l>nj_A zJ#C$RyPNADLqX8QBi1f|n|zKWzi;vN^>g!ere|Die>e=G12L{+$g=r&aQ=0Yf@J3w_Tb;rD??0+>N*3+BeXC z$-jK?!1sjNo{5X9kifvSj1pCvAV|dh58J#iJ$K9W^cEX;nKUtTU7+WuWDcqCzT z&3cH1tX?Mt?WdvS=s%8aT^z0JZ*E>4Ug992eHH*U?H}MXs%J1))6$It91HYVkcrS} z&Z1%jJc=Pm6CDl=<{x<~A=fUXWa=|N^PeA0Sa9#7FK4<$I|7AH!4g61XDB7yvN!gT znb)6ua#vjh^JHU?2M6gL61*Z$3Ea1~Cuyq|zVpbk(`x;rrF+~Omo)=YWo(27mO3pIXa{v6hjhkpW> z(@Fk^ytCxpPHVoO!rH^v2mOfxtv-p}&yDkuvaDRw)|A$v-A z&`-x95XJYfOrR}`FMy)t7IAQ+mW!2{ixVIrCx^u|gXRT7J2tX1w{s<*a#AY=s9W^@ znLA2GeX1RBezjK3EZ0Pk(wTb#jU~Zi5tcrJWuG4>p0acIubAJP`EnD- z9=Yrz{~|Ys58K;W*;kTpQGzB0px#+)Re-?B&cfm#|MAJ|i*21;-C;tP*+XudDZJ=O z>>_wG_eh_#jT}!GC6c2GBAb%?YU7vF@lutsb5a9@s=x4iR{&{N8>lSKK* zO4JL;x7+T4=hKBQbeY?D^Bf#(mw4Hu>*W0|GPO(D>Q|pFBhR(;u`kwT5|KUgRENei^b2ZFPC~oM!-uY~+{0}qzkhz`7ceh?%$@_AA7tfF z90TT)8#mQ((Bf6Q))@rAeR(>Q&Sf7uv$77Z+@G3cy=>*>rAH-8q{0J8-Cnc%95*1i zU`1|fx_-9FdHre+jwHjm~d-qLQ}Cumy9CB5^g>D>w7!ka-oP@N!sM~7AtzL>Y_WL zFj+{fm^t}NYs0Shk=|7tStRFjMrX~o_GT6lDR^Cn?cWc2%c&^^Y~2BH>4g4 zB$nSN2k&)u99j58X>!xA;10CQP9e^asUKWgQ@0!yT(xN?Z(rN_1&}J1?+W-u12%A{ zckoSCprhBxktsE9iOZ<19pHZrOSAG8`JeUKsjJrAERTpKpZws;wa<>OoFR*bOHz2N zdZ&n~dry5(U9#zeM-TX`N+#c9ee%lATQ)TlU6bYsxCLw0NWROM0h{>IcBh`2j*k&x zEI?RcmcS8+k%?gfpoFu2Y8B@oSf5 zxT%ou7UFh>v%^eRbwZHTEjfGa<&c!VyP*u+NuE6Af|RFbwnRB`93wSp27^@z!#y(5V-dMU7 z@bmx>R`~Pr{W(xg8l4Ltj3W+=1c8o)A-={E2suoBQ~5_OSs^78$8~B$10ybI zB$lTP^L8thgwryF_-lemfAs*_N#5%`=;EQ$BycQ)(=Ta$MB?WR{sL!E-0U5Qs~sl) z(4UH@157Zd(T*j+`&)EDfPI8vuVw9MU3Pg**M^}uEiY4UaJ!tSDs|9iH%}cc9Xp!g z?O!x8nEu?l==kKWsz_q$g&m)*?jI%ZW(Iiilf%atPq^oJ#Ast5?Ct2@+GLfNoJPJG zq+UDRh~piZy#W3ZfL#CJyoZrubO>A=CKwujX-BOl$aR~*?Fpj1ufOmK*UFOWto-C8 zV)-}w9%Lmph7A+5tOFro51JMQE@{di@9TxnKwh)679qeXiTDHQ#E+{n#=QQZC4OZd zu5*a6$J1?2j`s9Gh?66gj*vwNdG4>>YG+CQ&F2^qHp#AVJ-;lMe8$#Snr-3dUE&oF zkGtaDtWX5hFF3oRKRb343MQsz2Hz~c)8r|J4#}+mwxvU&V{^{lWAf0MCv*-DydsN4 zG+a{ZFV68i`!SKQQu*%fclQ51SxBBMtRV2d5%rwmb)W}E(p-p9Ns4x#5jj{|Dr-P( z2M*-1*O3?A8HZ<=vSX{iU25ek&U6&Ws-=2+CuINOsEBE69v5Aha}^TDx{G3@y-2oy z6UgK6iWFz>XJrLTi$b=)PefmIC9hs=sY9_4Q>Ot-ml&JP1k{uVM(}+0#Bq(2s4-De ztG4-dIG1&4WUQo_So_GkyRQCu($kIS_Vmd3RB`jnJ3KfmDOp`#p^Io(dWje*lsMSG zf8fMRyH3NZO30Uq?N1d)9*fcO{LB~iuWL$7L$IF=0BBS6>3vNj-&V? zV8gA_heO9Je1$)`*SonlTdhqk>etNr(={DZp+BOKB)+jA<31VmCnlD?T|;)4%x!W zrTM{uswDjJ+A(4i>06%MbO+LD;tO>C`^ewj zn`+16HPI-(*x7KTWkq4aw`WNq_sjBxJYwTVTf(%X1vz5x=$;*G6hj#si@l?YG9Ozs z^~TH%zkuPmDC0a@8R(qNJV-se2s6CcXjCl-fzgRSU4vWx5ay<<_3$d5naz`la>%^a z@ubWYkrUb69H#V^$(Ck>$latV13p6SAdjPuMw?q1SF_!m$peSZglpry1nC#*^126h ztytlj>gYM`mx?lA3>s{I2XbID*d8Mh?li!Kt%=_$R@csD7`(~yaK=IGW@u(VIK|3q z+qSqkBq-O}zBM7hkU93^UdyO}IIp0b^N2@G&g?_Msfou{JRPksU5p|M++E#Jh zt-UA;F*@w+xC)EuOB)ZPdz3uKW@j1q85_*NLpU;wUzjD}7E85?3wz?ujQbmVON1Ox zeqaqJHLEX1Q*c~{yxseV8*yKs>GI|Z?cLZhAy0n#!y*ZpK)#Fykcgt6E3<#G+TnLo z&m>@gm5tiY{dOL>TJx}uMwMCZo0e`r$*wAG*y^YVDNR%!3q&m`RV;%%PQa}#ol1$1 zEF)gMN#4DKY;CUI>R+0a|J3t$8$>f}lHaJ_>z(y(iqOZ1&CU0@iv) zA;iBiyUW?;*xxkfFcBDqK)?ZrwSJ=G!V{;K@ANMJB}l2=#u|LbTIiTZe$=zBEGocnOe}UiwN-XPmK^D!g(dbCjHBq|J)rb^6}#% zpJ$%_XhD!t{ne8rXd4RQ!2JL)tHSDJWI&Y;%?Ct098Z8{9M=@8@jx^F0$Y1wxZ}Tq z3|>4OWu|I|)p?9O={~sVsj`UV6Qk>+<9mmR1pl5Fa?%&M=Lb22`k}!He(dq~Ag{p^ zBzbe@ws5FKWBwNIdb z-UqAAQ=UhH8Gg7nGP^&wtiBqAHj@KJ#H(+XzI*YyV@EoCd=~j z3JMy4^a!&F@bPh0EpTrPxEyZO$9(&c_Qw00=I;8UVT%tX;c*HXE_*4|()9v78fwd) z*_P&s4D%vPsybZPVSfXRz!STl2w$L zq}Ru;SxoU{^Xy;DS6G8)(Vzj`5G0a&(8%K>|R@wqjg{QNO?!H0oAVWY?W{KN(nWHo^naNmS-XL z3BOsr2ys^TO({{&*%!Zl8;Nc`{m0=~s*||qVv_ax0mh*#n>rTPX2+~O&Nt*|qoj(O zF+)HIsU~k;_&Fp37aYiJ9r-59iq&NXc@SaoC^%7$pf8Z{mcpZZ@Qb+Mg+Q8%GwPZZ zs1WG22c;;*Dpc1=BUe+|6RS>{gJl&EtX{}!+_3KAkyY#V`+Egg*p#MbZ>cODnmCt{ zoRqOaw!5>wBtES=HZGc(2we`{VAm8(7aF3H8PdmkLwr)-cJ>)gB!1f{zqw)ag^6Xu zV~47cD8SFn*)uGvsFJ*!HjtBkaH4mlp<%G)nKx~6!-7H!;#-xn;KbOHiOQmjS%%(y zc0*sLe_pDfCJmMd+H4fL^6 zbt=LCW9P>AUPD3ez546wnyleWmviN*)iodN8SfjMiXIFLN~nt*t}hMYr#F_N&gRzX zWixM+M|S?XZ3x^5Yeka0&Kv+7dQoS~sa_rxN)P$R=pLM8z>iw`Y177llLB#I74eTS z>0rI^3m6jcE6kY9_B&cyn)7li(lZ-7Q^SLu<6cZ3PWp;W)QA2)QTyE7!deQ@ZOjSjsgD%Z47KvF7&1)jV!Xx{#QagkmUdyY-igFEl zy&)(1{?XUAKT_s3QQlJ$9#vmaSzlE=HjMTT)#a4tdSpiV=aV|%3?}%DVD&(q6fu_> zU>}=`Do6w7a;*!94@V@ZRScz$6W*z#{syY@k*42FBEZViX~D)h^T)04(mBqWz~gi&wPfImE#M;^<_gSq zxbZ5dNFMA>2~3SoQl~GeK%;q|3oK{!jF!1Y-7`GgOJ0xbj&dJ=L3ayT9o#atZd*L> z@JK~LYe!Ml3sVVuRySnF83af=P+a*!x5L-$jN}{?+Q z2hGd>Ja5uc@6Y@B{QsZN|JDm6P5Ykb%5T{!8d`IYg>w1xp7yDw(2{8g*;5p8Ms9h^t9^dsi$=R(sa7+zRfx zfcNp_JVfj%O;GhDlYcDF6MV3G_Qy=l zF1A*YdF1aK9p@*_VMiuxaE|X`badEZPfOHiSC`rIB%yJIdSjDcLC3CFC+1)Kv45f? z{7|nK&L?4iq`d#*D$B4{tZ!}VsjZ3$ zO3P|{)S|W z0))Cge=#=pql@I*KWx22Wr(P&8L1?%w{5(Ov!eguJAq`NIfp#Y7y!R-p{5f^C>Vir zYZ!z>xJd`zv)rib@AVhnr38fa+sLF$gZfbrGhVD4x-bUbf04X$m$izk)IbBi!{HFD zKEvaGoM$h{&djhSCKNJTECc?Qm$r7*SF2TT3>B0I3M%Fe#2Ur&^wxOU!-GYAmrL!m zbITL2Hr`2osD1KfB`@8@hvJ*RdvX|!P~D_ZHs-(_1onTW2MP>p z!^6}5UWo9n3%3GqJULbK%c_n(vveeE8%Q)WRFOkTRGH)z_(2H`7;f!dksI3IKoRt6hi zl&87{1MmhK$8y>C2o^lS3Xvya_z z__ui|GjGJoNd125*w&YvS5b7u$doCqDLXnOB3h-}{`THa)+~7cGSc0A=F;juOdqx% zGuTfSynr}16A?iF+&VPlJ*X0|3nIH>Gp5Zo`^SZYv1l0PC#QSJsfw|ph~(O?&aP!S zt4|CKPxh2&+A6Yxg1mwS&~m+G__jT0Y2}*Muu~@!Y}FecdB6M4A*3YVczIJ`XC6#% zG8^76Uw+nLG;56|c?~p?XR4`uvZe0%ox$YKY)88B6UX*@mpqPj2zfLE{Rxo6;7k)c zDp#zaGB!QV*kD^2r)=0BuswlOpu)inaGy=k3_3=_PD5meCdKb)VK+^2KsVxu{keEa zoRmJPHnE2`3@ajO64lC+6OCskLh?&8zer;gv!CpLnaumQMp@ms!ZWR_LsnXpb0i=j zbEsk)+=Pa@qNQ1jdiv^)$rtjMS<6}u*sbHl&evi82xE7`qY-GYhd7tz(E!u~u~-do zsG4I1SP)PsaohGxFuN7XC^v0zxoU6&Gm(*M%?E+ZI)Zx7Y@_|9)5lMb_Jyr0H&qmh z4?n=;FI6Wk%S_A4G^b?TA6QzLqb@-+oOYI%_n@x@AL;&ceWN) zoUgLcUX>DIlGLQD6_0IPl@-*TH4u1(mJ9QJ{5LhP(&;mDOz{bsO%LRT#b(8r8UpgF zHqUE4d%jDxuP;bEuj~-{lHv{}d5O1SAk)@d`)PGcF2E?9izax`nZb;1I0w?}F#+6g zA$u1yz*2xE@TbeV4PZN1n73m4Eq1s#;R;@^KSA7-f1KeUFxV5<89-fUnKR>RsqeuL zV8$_n?U_YyEF0g|cr``#)llOP=2E?I^_EcKV%jIRPMobDVRdDg%^8;`YfB1MK{iX% zGnszbnKdW1tYCIe=QcIe#hdbCRsJwx&`|P4suXgQTyZ)Xd4_32Z^eINd$OSy~pFVq*IWaM({cveSVpbANvCD0qyks(zH|Vt| zE46W5%`F{_0CqEEvnj^Hn=tkjj-?II(>2;$--h%-diup3ALYv) z`?x5Mc%S@w&nI^pZ5@GqdF)5#XQ%d~)D6f=u&zsng30UkU3VOeixlRryg!`VG17qO z?~hdt4HOvkEev~0QBFZnc!Vv{*y@?nxb4ClSAN|L>n1!_-~5%fmG(C5B}-js4!ju^ z`vK~PSA?eWUt43v?qxxs`4vMNpIlNVvbrV_#BMqG+2{q+T1ZQbweFVEM(g)R4-AE|1!p`A!9NsMl7Z=!5RPrg7Tf$b<= zE2LZ~WyM@+5KT(3q_AK-q8tnXvlogcJR%8(VatX?qI()PJz@*D-ZK?clB{093itE% z64M!uOl^`SX)-U}=Um!BqrwjREftau4d0HdwUD(6H$C$B_x*{6B zjtBD;KZh!n0>hzF1&2C#3>xS#RbO?v7+Pa>o&JPpthUUG`4= z?FfA#s?D|*g>iyqgVD60;C6B>KCt@$wgxZ; zXaK{o;I1mr-?62ciPC|S|V zt6xWT(-b8hTavjQ#PctOZa*V9Z+l8gT{b6;4A2^5c@9fZ#6Vnb67q@6tuFjBCf*`V zuLg1X%_pw*81kcM#6@0zV7JcGU)vELp$$E~S4PCe>ywP}Eb@0YmLbN`{~_qG7MDfO zcoSFg9|t9<{Zl@Spce$`#0`tfCj#5nB4cZP&UhQ=?~`O0O(1lt$7XfNp^xJ`sS zki6_<%hmB%M#w`0Sn(?DReTqQi&J1luxgf+HRmr1-C{L?{gl}V!MK{bblj)b|L2XR zvd=bV$g|m-vpU(o4laS4cULxa&dUj~4#-QB5G(O@-Lu2aBx3Z!V)*m)YMr<-&2VUO zOU0U@?vY3yZ4ueL7w_dmo#A)dPe6-1GO^sJ``olpL;wL1l=Wi){Z!aH?%&|^pN;8J znVhwbW*(wVG|VSDvf1eav3bCI<2(A(BTh5*%nG~y@L!%s)#>5>jW;}4Gxxa6dTSmw z30FRd%@+a_t-~BKzg6?@*V@*q*0MHf610^O?CsIqkNZ zEd%6_m)lNjoG)9_R2kqUK_}OeFVS8A{}oR4+_>U`CrzrL0kdIc6t^i$1U6G4(EZpK zsuqt9Rt3b0qP>DklDw)4%N23M6&1oq7k{$lSkaoM`^rN62+e!*2L=kGc9HKqio)e# zRpIE$givWp%4;oYSVwL_^NUFzVTZmGx?M3X6XcV$g}~=f%7cT|2Ls3fQm}T-hCy%% z;6JeeP(>O8ZDF-nQbeNPa|>6*D~*x!x{P^?7R>wVy00xf_&`ExA}t`GHHW-vCpVmb z7)5257mv0ay|+BxYICF~XndXfh=`s|RRiRN0CrwM)?$do=KzO*tPxX*{rOBNp4D-9 zw%a$s=!tWyItO&|A;M;MLr6ySqhq7(Y)f;VJ)9S6+exzyEge2UZsCQ8*@PLa_}HbK zz@Vk5^}Jk_Vb>a!?OW$l&+G&2BZBx36&{y2qv=B!`5t#9KQ%hG*Ne3 zYxR<<^w2HKnmgvl>x!b}zR^7s%{8^zqlJcu+xpw<%Je3?!QQ_OwU0Iz7W8I^?C(ii zP@J5m^2-R=+}quln>#NjN5KA#$a7Ap46{LCyW=0)L$CYAy z0RJYEvR4m}l|HgJSw_pea;2CX1jD#CXgU}20=Nz$-*&kD9BHp~F3%3*xcx=~*wQuH zW!zDU?Hcd8yO9XCYivs__n;!^Ndq?Ps05dGEpxn`eq69tZChPmE=Xi8s2=q$$b6kZ zMf2lr=J3RYvXYz)l>s@LmY9Hu3AFsK2(c+wM}DY#Rd;?VI^84H7dXTEL8w^Ij6g#H z?FCqytMg)(0*cwQPKC#$as#XZd;_hZZTX5P&ejKT6oMrBVE%mOvO}xX;yd=mPu7UW z+R>kHwROx}?=2AJqX#uggIJoDSyquSS~XPpb03OukVd4|2lcFbwonw#s7$qLeWLO;eXP@m|rD zQAdGDW9VJzGw}YH;NqfJcCy5+F;=~ytv+d#B!+Y+!gjLlQDTC>v$o3-CXAG*wZ?YM zVb2iuAR0d?R!MVWwx{2g*O}MZPHw*4x<(u(Bq7^1zl+*;^pUaRNJjxwAV5#dz{>!@ zcHp(Ky@(JfhdXnk;48#YBOfv?sa`jeY2oG20+u%xY}pd2$~EVCWv!gb%NQT+>&)A* zVP}#y$hu~0e9|^rZEve-WYn>+IK4Pan!Gq;!@|nZ{$_jMgAOmml83~17cA+m!8F(a zgH3@C!(Ga70X5!Rp)y>`Rn6u{|HV=sZR(NB*{3au=abh+W%B62`IQB0lQ{wQh}5By zy5QGqwj?Uiu0P4gHm!VcJtENMa_74-OktQftGPLX?V}WBqRn?kNRuF8Yn|4;i4N+8QRs|xDYS@#JF!2vVneSjV>CEDLS1!0o4qxu zlGtyaYPLCcpXu+8D>6s7F3Pu8?_9jGp?q*+Z9vuCE!Mi}Ba073%Pq3<8e46ts-YrQ zno?4i8WWeWatYQoI!2|85tt9B2Go)2k&P*%E{erk0~Cqfupe&k!Y4K0U3>tM@46Bg zKq_MLd2l)pQ;Dwv_NDIm0A*#2h@HJvPCY z8+n2sM#g5#2fKXOS)9EseQABId?fYbDwRrE5Qm%e{L-uzHk?rv!0R&l2`=}>lKFuI z-P>D~N!LAEPLkIJx?`mgp=jmx-wu+GlPjZ2{QPUfLp?n4y69iQ*@1Ad;Y6s0<#|8? zjV)3|j`HVja>GHq&)EbOq~LL z4gITgd){#FlUnTjFcr66Dka*`r*BOZmhL85*v*?y7By~soTXWAS}8H<}sd$ok)qmYwF@9&k@H>2M_leHZ`N&P&kSK_!V%#1sjw+s3{wQ@j{`9K&>=#?n)W8Po5$#Iu8oGytuXuVQ_`OOF}dt z)zi=A&ucsW;GtvBl0W1&pIIV{h(aUIA3qFce;7iXB40iCyg&TUFQAw9N^!6s{8MrK z5%Pl$G6i|f zuyxh=!Yp654=W&0aDS_rys0!Nqb(&pN1U}B&dVGwdY{adC}jcM0@|CMa)lqCJSX*M z<*`~5qr1s6#F5FI4~xY=kn--@vN3KACm@tKQzUU7-mDP`$dZnX*i_ovsj*QR({VOv zdZz4^z8QF7fc>3x*KJ66Wq-d|3{7S&cdo)~xlC9(javF#Mcyn`PV{eDVgxh>ce;|F z>q6U9QsvV!WN|sFfD8r?rH$P+?0smuy)#Tl}L&w!H1PuTl ztRVN?br6_KxUQ-$#&=?EDsr6{gNv*|kRW*;Ta5D{ropIBgf1|^h&TEuh$<<0lNaviA3LA?HPy4n z=uEi(++zo~5_}<(;i;|rA}AnPAx5_$GkmSr#MFsl7K~70X+HS<@z0!-RiC9-%H>2% zqc>7J8`3I23*m%GFBQ{LE#$>3m&iBl52LMU9mW~pqll{@ODXO$oa=XQc_u7A$`esA zlQu_I#8s*DPHDQ08ydld&R(K}`ga(oRQugK9M0Qp>_b_+91sE9UkSPz%*~nBJJ|m8 zBUl7BRg|6fstrT{ctd})k9Ha8z~@Ntz5zTE1KXJhg)N2J2geoSIixXN)Zq6hDd13n zGmgukEh~qf9j)!HOiHRW7HV>2f}AV~F(m!!ZNA_|GF~MVs>O5T!E2u4bv_?wIur&|3&QyA2*) zv%E99Vis~kp#P!yuGJw|kj1_acE1h=-vtAEofs{hLnTYO}g-+|p4R%h@jO93jeX)yCH}C?R zg?5sYVJ;T{Yr+c=JErvmR$ISJnhZ|NKpdhdjl$Q%P|1KI!23 za^Y6=HV8|^L^Q7yCGCS7tNDET@@ZR*0R$!?Xg(p;^w401oHxCUwuUDU^`_C8smf`6 zVx%xG6D&=2<3(%qAG8xU?!$5cKMsEH82CLu4<29?T<5}j^)7c8=|M{*Wqfd=i;ETy(DD!!NM!FR>m zH$g9B;51Ys?s3B2kt*1_w9M^fu*HBvy7DwPmp~zLl$A@lFrgi?W6(tUn+o|z_Zm5` zC{gB|6pNTK8L^%9Eov{eH&-sDS4;AHv!>V2Qxnolo5FqApMS`h0Gi>n->v-dmP4nu+Gic# zt?&{_bqG=40N2h3qM^V^0iqzrgeX){Ke6`u_mf*>1ql+ONFrj!rE^%yM@{-$c!5W@~HK-t4!hQ?54%3aX8*nQeW$$>W3&FJ$lt3sT ztHn`?!vxq4J!e2XA2FVkR>{af@6Zq*=P#OgU!FutSR|4$l($ILAo7V3NzgLsvvph~ z^C!E=4gS-75&9NFQ`L=f9*@4RGk{?D3c-OH$D9d>GmOwC8=vXJ2$$zaS%NuL5!11> z@I4VBVOcjWxa^ww4A53wvFdzQg0Q!7^|K$Gs+iHt;SUMF8t^ zzYoh|a&N5))+HyDgnNn1XCzt?S>+Qd^dX-h*HC|V@V&U>D6ySN^#e_>~V{ztaO+FlKR(K9Q!xoZ!ts zSnTtSY=x_7(3Q4O@CcZNIpq?+E0)8dDJaVDAd>T8B)d|9mBz&@c-Nh;it!c;W3j|} zQX*OVO4NJNaW)CrBMIg4Q_lXHaxK(g7KMjLNni&^GXJeDiXItyMG_SmIey16^mwvB z5J7(3$08DT(UL@Dzr)eY_+18C`*Pg!T0fG z1iy>8&8Q%%xPtBL6A%iV3)herpV1nv(h#r^A38ns<#{fFpwxz?+~xsp6p6N{lt?9J=+H)+p6PM8Gw zUo-0*@Vm`%OGc5j-FdJ^%=oO5L%3P{)@rSb$|iGK95_ z`Zo?y@T=%=%04+69#vV8e`wJmBzX20qq$Yr8Lf*mn>AW={}UTdp8U7}6>CtiO6dG7 zqg5n;;l|-;^Ul$|{kDc22if<-t0@Xahdwe)lQH#FrMa-(k{c3ZNm59qiljF)%MUo6 zdM_drhUsldtyw}&Ca7&}KjNSwLt+&K1q1|<#;eF+pUCbqnvth<-NLBs>cwC)m&t$Ve_Yo`AJbZ<11wP9qG1|o&w`v}5IL!v5mG-WE4;Q?w|^z*B~+;z|0yRM-n`PQV2 zROfWJ<748t|G$d!vFN)^cP zG;nu)26zW}$qdnLM#OG2Gr)ln@Gn#ajdowT(NvY_AAD|`RJu*fR!Ybri6nWURJw4e z|2dSI@1XO-)S)3!GF|{1%MZ<|wqLKscC!i^_mgW|QyU-0Vmr`i>Z3yPd0LPTze6UHH z5gzkoP$r5g7)Ct~s`b>zF`MY`Cn=+nJxz%vhu55Vu9sytrH2iMA==t^uWrBe>Xr{5 z>9lnHW9>t44bNMZ=*W*oeD1qvHOj|7h*0(PtHNA=k}EXICz5ou64G0>mOokIrPH9; zs!J%(@ZyK$ug|83uv-fI`U+c|C-q^P_$-<=Dk&){nB@~vzTlq9?8LChG;IQ*DSTs( zH73ToXSuF!Lw9NU)ZJCtS%n3OQNG@+U?%UxKlFJUCv&qlEzoD@=@(LecII!G%E{VL zl45Y~Ks4H@q`XkTpvOF4o02eZNknKyyH2IjC8X38X*isSgl?B^(NBS2O8}e=x^)W) zV0*;Mg7s@wt!_Cv=voKt>b6w3cgIP)%gfPENy#Cp)Z8<6$}E+VgR{QQaIy{cCQG;R zj>`GY-+AEX*DcTDrsQL(3XM;2Bid=sQv~QDxFIy%}u9)x@rjn!;4F8?38G8ZXI zCEnCYQWr{uZDg=Y{v5?Akdmb`SuB%?KP&vJ>Re4MkRVX1Ch`*`@8?U&8~IEad%60W zRJ}i0#2^75rf=4f7+Os0ej5I5gOV{pU5oIxv)St5P5 zOl6ACp!c{H3wqEfy&Ccm;2r0=7U4>!amIk{VkSnxm?XlbG$B6H5FF9X((SxEd6a4o z(*CrB`uh6_W0&$3akvE_i?T?6B$Vjlez@aF%UUvhEb?>O-PgI}6m z%iNWKTe2j~P>x}k8|w@JmI(CVLwy&YW}n5x5RYAl=y0#7VP^mMR?LFx84f`Mhj;(; zpSup-z3aR0cHfi#a&qSDA4p9H4;rNr#(VEIMmnc6k}sgwuC7`%I&t-%Qxg+Y|GYjl z?<>;T*NMEIE*T#$dHUtDO`FP(^dZ{S?!o_jk8>8#H*zWcA>gSC!vY3F)NQ!1PvhFw znFX=jTU1gQ7KZcT<^nY1-5(-u?v0uz3H3U z=r{fuok!bgb^e10nj{yJW5mZDKm6VXi*RGJHNaCfP)k*++}I2f8>%(zZ-OTjy4^|u zbW+IM%~#r*e1oANeB5S$#9&U)EPAjiGe19HVlTAeX8x&Zyu_Rfpm<&afGcv-E8VYSWCP{Qvi#{ec`}V#0hN!5pAEnZI zQ_LzyLYaRNS`)@#dO1HCNsWz7AB&e8`{wCmW2{q_gpACfpd??|>%sYuf>8(a>2a4O zg_7}>KUN>eQNdACDVvrJ%f#ExkOEP~L}+h;K9^rBE9455VTye7ZmIMa4J*g`tCYML z$L9+Rd}*Uf=QHQtQ%Semp_Q7bQp!;7Xgzt?^nJET+P@kb+OnLDN3hM!^dQHYWeRd30xn4N0jnEhg+0G%*7NON?vi734tXkMM z$vcK=hn(ma(CsLQh-S<|447|K1ZOFwsv1IScV})T(_PQt;q0FNizKT&KZ5*EaCsS< zd_G95;sM0ENtz%zlwU5YSd4&(&!Jb~9mcAN8Pl!`ba zjm0G$F+q59GMt~Ij}nw-zDSnO=JTCtU!whzg!p7<6T{Qr<%5|fpdHuK%RO5DN~@TBVBK$Xhb3rOayiMH&LcN|ToORrt4WNA_$ZJK3wK`pxHN!9F(L?F-{J$> zN4EYAH?q)QnWIs;m=hA>OhXq=NfJ^9a_poA*ds@;!b=yg+&F~39(a`nsICg12b_cJ zT;;%7F9uK#Uzt9aM|f9gwh-vj5a0&xV8CTSs{Dn^T5g=@$)v9bh$jh;VtPK@l2|Au zH%lb8JLC4>^cdg(YmQ5$F<$hoSzd|)F&dJ|tW(h&QDmn=N|J?M^5y(^@>O$khW``7 zSfofxv$08ums|pyL=kklm+-CH_@o#LYf43C(wD4stgOLMRB%$`u&ddtfx$sm8KL8Eh}M^7A=dx z+7Jm?n41n~@IIbnD!J&Xvtq5r?BsncP^$&$!Zf^Qa8@tCnj--7Dyhyf4if++EYJWs zHVp#=BRDOv3NRfbTdZYBnFhHO>Ey6wNqfQDd2SyvgfkE`Oiu8pACmhLDQn4B!x@B^ zP)Xy{k`+!r1rbc#x5asSE0Gb*mDAb-{G8}3C5KVQlYn!X_p z4g~*+Ja{*+c`6x|P}he}e%QK#uL&-MiwzgL)XA?LshQs7L{dq8gUP59hA2=>n0KIme zm@&f(Jl+5UPW>K4mO!%fNzT+H}YQ3UQz;kk0Sg+&{^1bh0oLD0`(VaQM zkS!ayFZw5abi8eVW9#c$W{6L{KRoit&W9JY^hL=LaXU7j5G|x9~>s!^^v$&#Ul(q=^N`pI||K`NT;-GcKyARZtFgj5ndO#%BMr-oe z)~2!6CL|(4!ZpIh`lR+F1Fc$9>&5D#qkK5P=1q&D4N8yo?~qJM+WSfCU2B#S)hUt5 zM15sN-8|5pSm0R}qk+0b4EuB7l|n}uAf+eRm}xrKB5$dSOLg$21^AjHu~uf(5n?ogHneEV;%IB-C#RukUVKPF_!!_?m6yvgG2t{9S zqv%9whw~(P^e5bh;Qe7P;+5ZSPoY2M7oE)$O&UWrZFi_w42+c(qORuV1<_J#d0u{F zqpd8_mc&d@LTAif|0F-W4g>aLPy<43N%v3XW;-1 zzPAHpJ-aZhB9w`M!gFEe03{62f(BD_EHRke_ZP^_k0qf`g?$AGY*% zW~9u2fII(QcIfjvJ}$6S%0?GLGuE#c5d$^;2L+^(SO55pFYnt4htvW`FOS@IKd~5Y zM&9_rr1#yYgo21jO`JO0FSViJb$YC2N2xZJClsLQf8W07^kq`@<>5{7A>m5B#NJcb z${z1IMA?2K$Zr((#M|8Z4)Oy{g=PavclidYXhOXS&dI$#tirChbnqz*_o%eNRRhQJ z1S8==|0!?)%M^G3Y|?45Ts=pbzG1_?xlLAOohUJ1r;F0c@2g)`WldGZl(8bMQjwy+ zef?xznIg?rn?wFoBi@y~$?51oUJqDGEIG%sknyeZU&fZ4u13`Woa8qfe-M(k%|a5Joo#D2G5D z(ZJo*z%J|^p*;&P7}Oj#nyHg!a};Cl2pgCAQ~INKa}{_DKaDG;)GuRvU7oc&)rTD) zAw(YUKl9UDPrj4HFHI`Q%+y5&`1f61TwZy#wQOLju9H0Dkc}?>`ToIXOG#UK`(vY$ z$=7#Q)gRsd;)5sA4@a%@iz9l-6&+iGbAnT+yfe*>ImwyCZJCbcmN?(IC|xaiVC>5+ zEBaQvSlb%alOLIE(dQE0)A^3kR`Sit&J=BW&KhD}$2`rTw$-9asBJLCPjR;87HvB{ z&|HGnHf3hUuwsQp=k6Fc2>R^WBtl0sFF@I;~8!?&Wm;WN)CAZ&zD%N@w ze0WMcuz6rurA6^X4;oy zT}D_3Gxp4@Ih`fTY(u`^w>J|a@`roY9X*fg5F71o<0nUj$Yu53_IPzx>{OS%BHe4D zdAKk`=Hty#8vHbtlr$~Jo10EPi|m@7Wvi;n?zUHwzhx%Z9H4d28y~fGo4%g7=|R47 z$3J`KyL8QSKkx|09mk7ge{^r>8Ux_E-}P#ald!56b>{*hD-HoCWE%#pdiK$RJl` zWpsqSkfZKFlz?4K4oh>n&8 zITc%0A6kkYOl<7(LHlBb1q-r2IpeKA#>gPM^@ZN zKiZX(`Gq_>|A<cRH20gAex=?`c;%w?09VXNTX^^<6-AmmceWi_3z5w&~bIs*cSV_O$%cyyerd&t!W2# z?z~qSo1cvS7+zgn>W;sRH-Hbd9vzT3xi-Ppl2U)nhS``b#{rnfn%zgl zzLg7dhmrcOc}=c3hnWE_)3^4w7;libU4#vMx+H$3AvyiEEz9ODs!xaW+p%&(#MVVY5)g@#rtBJGbm7{}5fjW3!`r z-_*)_^yo|EbWM&{<|#==@v5@SEIZtS^_iwLGrQb88W(|MmG{kS^rwMGa5oE1yg?@@ z7P#UL6|V3w1U$<_=MG(%gVdQ3=o-J}N?idAoR7gF?praG<8ikLB zt6R}j*}VeMn(;%+#{>sj(#lyf&!Er>`$k7cjN^$tue@^bg(PlSlBKoMkJx)n#a*AwAkt*$TE@+dV2k|9lkWEc)4CMt0=&8*c20+Lt4e`p4( z%^JjviQofXf8_y2K76;A#99W7b`_`E=NoeR_6B(u;uXxdczgLJ zife|s8MdhA__OhC=E+n2A6-mc5u(%u!<&Z z*+f>stWN~@LVx0k#^k!^dsYIbf zv3cdA+5@fF6g}vh1G;6r{xxB5cSDs^4p5hy!1TBB8SCp z4!EBC=JJk5&H+C2Aagv2U=5WXL$C^Jzk-INh)aZ?Ob|66cL%^qX2j$QE$+k@e{MDg zVY|Uz8AD)5fVc3-C-_-gj zgW>%}TzpEw1PoSbSQ)EHE@)R5?3#Rd+t7v>%O4A>x?@v>1>^oz>VWvDs8z??AMtGO zZfg5EAlQ(n5Tc^NKliV#?E;0HuX(9qKBgLG6024VHm(?>SDK)3;67s%`(Dk!d=2^3h4q-4ML#Tq>eKyjN&O3g7YA`-9 z&v#!<-A5OnL@RvH)|-gNoLKV9hDDXd6-DC(j!Ij|uMMA%H8*x%oGK*;O$8=pxyqdr zABXjJc`O2t;94n^&Rweosk?B=t!RQXUOZ11ioY&HcWDqcnqpReU~kohOJ~mfQ&Yk5 z?}Wx1>OibJwoy3}+w*uRdAGMXeST)NfMD+ZO=vbOnDfz~7oPBVru)?H9$9!SFFVxV&ri^g`hWcSUc`x%nGA{5zPa-^6j?+8 znG#KgqG<5Z-j;7tObdMjthp7}O#T6EI929f8Ah5_sYEfltKf&n{laiZI`$us8+nEU zAMNnMb#so3JG_cot$g@E=C;9SCl7x5B6*Fx|IH84CKP%Hx*}>2)BhwN z-`6|%;6K~#$kWzbH%XM#w%pN`Vu+H(D&tCYQ8AfyVVNZ@C&{1pZ#eTj6iftY-4#6O z0(mfRUW0kVy&lc*0y_Xo8L%N>r+`ankf{76eZ$kNu)n}T)~z`+df@(?9`5+YzXuQF zbpu<z6rU@``Sz9SP<^W4exb)UGq~;R=GW|A#td< zY~R#t$IdmKyFwm)ECSjj{f+s%;B04D0=Q;qlqR?BX@I z8%;^aDf!;K0=!rO@`Vbcw;Q>_UwWPt2L_jj0kU9A$2C)TT8Hb2Mjkbf!|efhj1}ZR zMuW?}2nIQJ{#q_8OdOS@jxs>ts>yChsns^B712K4#hopRyC3)V8#l@$p>u;nzEKuv zPf-?<_gzkwF#}m4#4eRSmV-=j=@q%te=4G*3W-65FoX~>YD$Z*#EOVw=cqg>)*Fa- z)x9Qx_7aZ;SdxG$T_VKf&IOSQrt8k$R4PfoB_U6#o;L?o&04oRI^dmo95`lR1pei? zjLbA(3FFA=IVnh!PDxpk;sue#e_VQX{dUIHrH=0KpkV)p>IEC3uNhRjJZpB|rukc6 zvG;TA_isOm@=91~=C#|a>X@4NgB^{H9VoCSO6rTe0{{Yzxi}&hYhgZb`SAQwqv=l_;~4JB5j9)=2X4)tw2IL_0iM0Y@8Mb!D%Oz{fg| zRUUg>ocxOqoWTr~rNCr9Pp*>6O#iFU4D9@GnCfx?R3o2@XMe}j8G`|{n_(<;IJp84 z)VG6X$JQFWHYzv8D0Bt=;RP3;dbFk^X21~! zTIMHgR*EKl%S5S6u5#+XJ>OkfT5KarN;~Yfy0p@!Hrk!R0c^P{I!$EnfAPRJJ+DBo zw}$J#DAzHU{}NP+>d|>P$80icwbrWT?};L0TB%YWncaVOr0ed&FvHzsWv29QTEb;Mw7^s8K z<-?T@*b?CP;0y)CfbSsTF*bD-SxqUm%!oE~+^@2H6t31e-k>L>4%gpLBemYK8}qFq zW(w(SE-0H{QmoZSbL=$zRBqBWX%0;!4Tvi}#jxd%^{ynCXydL`+afKW^yC!M7Z(pj z$7Pw82Tyh{c%?vARXN`~cv*Gdn1no7pU_xMo=Hw`EbWVqD@uyyYE)Yn>^V{(yInlr zSFpUQVS#S|8WhyeUx!*vso=|T4fJ>5M-S*NAQx<}?!A3#P#!k84E|S zMyOh0mj{c+ESN1?&2bPEE}G*auz~^)**wPY)6ef-cH+usMs1!a*VCJ3+4Wvyjer}- z;we;(5jk08KrC<3m?1ZqTohf?*f3<2saCETP84akq-YE|3t2fOg=@VN4B2^IlDtjp zo>|=3D_1`K=Ymo~J`J98(ZOvw(NUhBv2|7NKPenxi&E@XEj5**Ad)RSODS;aRGo|1;u_@kC9N-S@rU9!#iCnP~ekh0mT_NhqBu-*M&3W0%QrL|<{Ng8X4>WQk?p*gubDw{$n}JiD*r(%1b@lvJ#2e>5~_pDhMX zoTVm3`atqyL3*^Ywqegp15HgMZ<1%!3AIacT&TZ!nf4v+eve3ezK=?}apE0^0M|p@ z!jTIKQ;-efrD%_GY8OY8ls-M;%#&W;VaD1Bflq=P(L%l6gcePu$B5M;iRy_c0TB~MtW~`rWaX8C;q#l|jrc@~q2#*G!uNZg`;sL|>dWS4qahLPg;sAFq5C{aE^5nwYMj z-D6qDimoll8)_mRCF`BZ#3^*l(^HIU_)AgB!eL$*d7~{p(-iORPp8&M+TlFN{m{Du zGe#J0RP+~vc9B709VHdvu`1x5LCQ|3eKHL4TxNoGg7)mebtl#|-L8pFNsTv3gVTar zdh(m%GQ2{4{MRpI`mgZ`-~D#qt_wae>q-(C)lCkk_W1?ySwjcw@*^~z$fVF@K+!>aS)grtx{skT^ROntPRpN+N6KDO5YmT^*PgLvbrKF3?_g{ z!k^2GDzI85;j#s6i_qUU5aptO1P0V5Wug42?$ZIu>kC`6d<-K&zOtpGn}~bD)ahhk z3|r7sY}7@mg4p52<%YvBh22LKO>7b%MNB1m_?_VUp!E#PBJk#A!VY@i@0xGtc`I?^ zu^DjQ&<(f27f^?(K|Ofr*b;TPIWj)RU?|^5ey$k~^AD4<5NqQgZGO5W8qt@kS5;}E z5~Y#W8^68hzayGZ`3q(2*QZoWPAKW65&1x!{(f>jp{1S+`(4yd;Y>Y*hX?y%sWUyJ zky{~g`x#RSL|`8P1dM1f0kL{R`Fd}bF`n)nx_qF1cZeV}Avv0(0$MUpch}IDYL){X zI$5Ok&or-)%=$o4L6SC%9wASq9f}NNzn;BFA#ti=U{jay;NHAU*MSVPJaRyaxS_-K z1<$2CGTxd6vam!c*@>x64S=LD71Q7Xi7pI-odvj5+>ONK(qXKWK&B1!_V(8+xI~3s z5a!*_&($P9*N%l*glxlXc7Z9Ws%ooGU{<<62U&X?V!|YT(S9-H%Km6o>WQmNX@bpS z$*W3_|4HG`vIQmTG8b|a+(P|aKxp;(?ldsai8Z=!u#6EU z;~rR>0#@cyLf7^d<)0VX7BLDl9X9Z-z|*ye3c36E&;} z#?ZOfei6kZw)tp30N4`X&mb&fL3aj>YSJlIWs15Zd98H4X-IJX^=hgK~&@`b$9l! zQHPTsLKIts{`E>`UStSgR6#ZXh%`n!O`2%d#@Hynt&7m z6+xwF?4qbB3M%&Ad)HVJjYgB$jVYFBG%+SIHrU61-tK|=efj>s7=*)pW#&zvd9%Fv zrVl8SYgmFOIAp<~wei4Q806sr$w+Od4DV=@AZ;xxE4Oqcw0FsF&555n#L;&|nTd`i z${ua1p^mRgEUe?3P>Rgk##|^guyOM=_rurr?HpBn*)&Z}UEMWLmc*d^=)(E{iK&K; zwYkX7*0BDInD&U11~~`NOAEq?9UjWYd-nRe)a0CEi!*v$qRgfHW#6sir z6#a#r$a#p^!MNJ?c>aN=jEs_)jz84#*pe7Ob5)Tu^&NOmR_wj8n`h5@j!MVpj4nW| zlb^M=(B;ah4~=cMuW+%o(SbzSDAzD7JD07E{wY9GjHFwUi#^H&Yr75X}BDzQ?&HN^#yICGcyR9X@jv@DOcjka&{KU)HMP+Y1#WM_CHdq& z1t(WO$O1y+pf*TUN6!2lP4hIuNm{ZdNHvZxh#G@s^*|W>9p)WC;bXw>N!n_v>du-` z$VlSlYpbJ|Yow#?7A4cQ>k3n}wAV0kHMg_bblWf>RCcp2L|Mny`0aILOX1JLkT3~* zSI5*Fu_^|dnkXp1J+MrmEl^U`^TH`0A4uXdCH+ z@*-`*?QIiGJfef5b&OFI+8I?e!PkW{R8#ae6+5ZvJBUO_!?I&qu^;7aIAjQxI=~*C zKwpe!qJR=X2a|R?gS#YAK2FYBLWw$|Pcawn8{D_zhkfhAuF1v+_bsRvD5@uvmrwDz zw7|kC+&Vs%3Rq-m6crmF)-=`;H88~a|QtEpAz;~yeZ*P)@16}#V2I- zhwbd**+$CEz-|auF(&lV|2Le$75XSS0XqS-#{-CXFBTXLKq8;{YAC*nTLP3qSPQN- z06ah~^c7sv)s~m!DRq^`C8t)pL#^KYSr1BsG1MyLg1r+SL{=PQq6cMvX!~kr}0NW8B0kG=AWg;Rwbo>Hi!9 zbdpDIxDZ=b@Sj#Jpa>3zD`UZ4)^->wxLB(7u}kXDmJ!D@D;l_6cmfcPs(UX zO)SvXQdP7Sy9YQpL|MQaZ6lqBNY2(5{BXwDe)7b*RF8=y2-^%blSIY3EOvlbD5BR< zMWZ5RlqneBmIg+enihWI;Wr(^lAz2GXhs1?QI9}gyAN33oB>O+hmbMiZkYqyeXNb; zR+_h>AxW|c;F`JItCUiYCQd#!Cp#S#nrj3%s%ct=k1-4v*#
Y(BRji6-58t2q& zNNsPCw+Fr!@!H&J_!yCv@yVIJK2gUIX+Fm5i4(}o*U#D9agr;Bt*@(Y5*O8ORvE0rbP2?r&z zi2IS5i+^LWGn)CnY<6Dyyyf_zj@{(I-0xqkj!LPii#m>fdi5-$5Un_UR}kzIwRPlY zPP*m?&>e|wg1RCub@9Y{s{-xVxBihpCprC3ne~D!sLLicC117Z>8;Cq&NhUUx!N+Q z)Rr*ogPL1g@QtkpT!z1{UwrFV=EmRGnm(I5fI~F}1u~yLAdq}9YJDr{Vm65S zoO}s_+wtUf_AUQB{SuysC_mz#wb2pLFWDR_nmxRpj$?M>aqVmkJV9{t3-bnW11&l1 zNIKJ&hIew1&UN~Hoe>xnoGl1a4PGk2yup9n>TbpF3p`LAig@;3u^_8`?;q1Ax6J9y z+8K#EDb>-FowE@$Z4U}ZH4`tzJIGcodDXvkm5n*dT_A^L1rLh|b_LyqB=EO{S+Sl? zTfd&#v7TDamI#8`=afF+6poeR!i*(+M!`8g5;zKm0qk&+h}1BPp&1IP zrXkEG9DL^>f0{ssj?g&g(Y%@`S;4?>YLPLdi&l9bFiWySZ`>1{G>%;Quf=76b>G|N)Qh4h(KEM zxhW`GCi3!Qpr8^LGRGh}B>!~_G<;O$ilfRF4#H1C{9-#ZvN1hT>jD9_u8;>6A28gq zSwI7qY#XQ7Bs1dVr z0P4rraWHE8BW5-{2b@Z3W60?kBe?m;833Sl zCCuy@)BpOXdB!?f+SzkyvUQXRzCLr>v^mI;w(I-$+~~%}(WhvL@dC^P`bClCQ9-q+ zfM&twkFfbJv=wa=1iwE6)E>zkCC^5}JFa)Zx-bTwl|K$66nEiGC-9H>$r0SM8CfB- zEnxCnlCexvFEkeGZDLw_>zH|D4ljUlAR( zq6xs0V?cI#v0qWEsUG%Q$^~%L2jin)yfWDXoIf`@3J+a}o%f?!G!X`Av3n_hnqgN^ z#r(NK4L&m##sE({Lg*c2l0FhKV|(Aw!F@l{xB3p#!&fod?aOG}XU;ZAh z4=&J|7iVK}ZjPPYN`UeT&bgua4sIm+Ll>`bNY5MBv~5QNN{aTK*t9`;#p3g$%T`Rb zFYsUb`OMMg9z!=ZolWr4F)DJj3SQ+DmADm;Lr95M)plxLP1aow>z)@V0)5MQ8ctS; z2t#f$B~m0r+VRlmC)I6go}${`)zNiycwEnuX)`B`f#T^Kk7rJca264bnt*^0&WglKkeGYspBWzTDVMk@#4j?AtAAg z^Rq%-l>L$>PWk=Lv{~^xYD7!~+i)2PN3%@-cbYY9dRd+$@a?q$Q4;oSrm*|6u8^Z|%*TL1_m zIc*^8nQy^_t&&uUK`S>&aBc*!rgzoy~(nWDU9=${EI)X<6b*-4fn zx2*|pAK#v_ptjKyHO7co3wdxj0A`YPNDxKzSN6!oPKu zmZG5aOs2{(uflR#-&5LXnk7ot;crYS=lU6)PQjWw*7{#QH^D@E?*;njO9o)oc<_hHEok z3tI;Kf+Rs9%q_4KiL?QLX&8(`cI{H_>SCm8dL7|D9X!{61v*3?=AJW>9G=gs+a{5QuGw?o0??F9J|9Azr z6?J!`GiRa0@sfOeS)kbW1^OCi!Wh^ElEN68gHwW}U0v{rgJ1AH;N0pX_@UV2V^ru9 zwjt;ceBW(mKe1}5Vi$a?Bv@H^GJJ0ja-=kudPUa_@nH8*n#;VR07rCJar4rp9FpWX zhBf{Z$1w5#!Z8^SqY3@~LT`t$q>sXYHW}bM10`*~NhiI%wC3uynlWQ)u3fDuU4!4i z+iO+fU2s>fPhYTL+Kn627c8899gW7TFfSkQcDUzw;1l^k&YS}jCLNRyjkQ~+P3Y=c zw2Fv_r%iKe#)5db^I&#!2%gIPF{*L-T{U|vGMoL)sXq+h}RBHHe@ z6-V-ufmU1UfmZ8E7eoa|jeh9W^um6BCls zBQ}mPv5p*Vqi(|C0x3xPUqH@lJ#<+mvXb1h2jdsaOOOk^43bdwg<1H=($a1ef=`>+ zRLf$Nl}%6xdNvKI;5XCo@HV#)kXZo3BA|h#06RxNAQ@q{0WA%pacS4OMfh^Jwey6@ zZ9p|>B$dVfwZu2Fn%V0&92{ z^fIEMB*%u9m?HRJVEyNU7ta^`y>`o!=HJ$kG1M2VFO2h|z9L^_ELrC;jOBQ8KpjgE zefS)HkKY|YV{q3w#2~>z+(8HtT?X~M4voNmWGv7P*&|307%3#Gm_Ecl-nbnv+=5Jz z1>M!FgIefHHl5l|)&et&mcsL&=wVvQ8d4_gpJ3NNqMT}}jjdH|7NG$O@=XeYWYF83 z@9T)b_Z1_581(1$}g!`EH^A_TF?0NJasf}AOssJ3#LZQtx-(t7O<3*x$?@;HM zmyX|byBVO4<6|oX!G5vZN45{OH0wco?d_v!3ZHO|#|n|jLJfrQY(x)p0=N^w*E=l8 z;X3jR_`z}q!BB^D_uy{w2QADT4rutS9besd^x!@u?QBRY6V9F#7>-}(S+|z=Y+P?+ zq?KvvBHncf?$w2zJZf#=i7!ud*6+<}dR0Gqx*1R|;0|ygAfD!b`@~4@6N6nVsEJFO zw;ej1OVMp4*^F%Pk#9zvEGfA>>J+tVTSs>m@re)NX-G8It#7(_CBQ;(8w2wKy?o*m z$MmJqJJ|VDBzu&q6$C%Se?PiA?#8rkUfhp(Ce8D{L?e`06YT! z5nMeIhyYhsoL?;OZ_Hzfj~a79WZo+li13?!ybI5O{_NRsnM~JsXk}G&%Be|B|NO4+ zW{v-$;$w@!Uyeb(sHqO$7K)Os_3I`-c-BkNXvjluJ%T6q5Ac9b%>5C#Y zSppEPA34XgZ~cr{`=)449C^sy4D?=bU&N8J2}bXSmir%}B=>pz2?o~!ok@0wL`aZ^ zn{de}vO)9)m=sZNlQ5hMTSv`fm&oxR3G4FyF~NCcUnW3P3Fi1V`MfOrJID+;N3i_K z%qmDEVDT6D_q)&=`ZhGT_JKe3^i8&cTHFV2FY8TRl#dOAu^b~*IXpx-hGQlvw7ublzN0uL}!eG6++`JPk!^`pK_$*$IN}%c`5CA(| zI%4VKys|OFJC_eH0pIu}o(cPsp$Ie)&&J1pn^HM;(%;XgRE=wbqv7eEA^n$0pKOlv z!8!uSz%Pa{9`7GYnQzCh#Qjh3Im-Fzv>tq>amodpF{vXajyPF+(97Ys93;!WSs%%kir|Yx64dS~$O9UvM0Hi#?_UG@5WAa>`>)ImYmd-;xKTjA{h+Ge-Y3lg;l-lci7bD>}HF;V1hi-FmYOuAX zk)@Wg2Lys(3*_XOPJokGrT`%q0PDmc@9_wxmC5Mc#$-Gr&&>w9(ue0jzryVbk(C0( zo4A|__`o88KE4M&>5upx3Ys!^b~8}ZgE#mcQhH5~>^s!4ti6klfjNkdfw&T{XFlzBu^6Z~q{3U>5#=1Tv=suGe0}o6$Ge7nLF_h-~M8 zZ2ktjQX8lhI0_wM>tN5o(*iBn1MdS9c>ufC!sdV=eN=>o02c@MU1Z;)w{#SHj{-*x zLCpdm59WAw&UY%`{0t;1N{@e=a`XRF)eEtn$*zxx^$cAt`oN^JMq2DrNb@kb4HG~@)Ref zwjfP+EoEkA=npQ^_)~bwX?P1#nvby+x9+_D7fce<|A~#OM2LX%fdz6K*MmtKJO139 zu^RX>a#+6f)W{@!^;CA6ckHj|?!~#CAudcm4w$s0@f(EPv6~*i9}Vzqr1$@u4=mR! zyLj8M-V;tNaU85&VdHJrTI);@PI3>qU!GAg# zL17A|5ZnKR(HPh>!PQ6hvkt@$fon)>FGd63Ub5s^K}OSrJ>#2^1HSDS_3QcU{7Idy z7k-@I5`<>=DWLO4_yxxN8Ni+yWBRay5WHXoBm$P?{9m|t$~nMRIwXUk#2B-=n#k_J zJgbvuFE{rgo?>;f1BQnBO{L;Bl99+hfog$N+0{ZueV`clo;2EyiOTY7fjWS4EciHk{r0tg_zne1|8# zejatYdFb}_)=4r)b{1M|h+mL>&jT8E20R15gU*usygY4K=`hatrm4b19>yT;%ah z_MHcFaW>Nj9nR$8&6rIlE5jYR3`k5Y8jY_p{VanzaSabI+RyEQzzaRzxJ~wRX9#mD zjsx6-r|~f^J|Jb#`-N*@H}%YlL-Oz~1GA#AVPulEb513nT#Ve&l@4bgz|p{Wa9^8x zdH`7iYcS5R#((0Q^MC&*zR4V91`2rYA>$A9tI5U2x%+PejvJ?q2MjtsZVAS>KmPOi z^Ur3_p7HFr&t~H*n&$C#&bjXX-X8fLc420k=*qKxg{IbDe{F4UYW*$4v&>x6H+)TJ zc%Y7Dz8kDJ5AR@-V80*7&xrcq{o{{hM^pXIDU%2umM=Y#m&}O{moyL^4`#K7;3nop z{-h;S;BuEcb_KHy_#5UWbk5H!`qV%El)o1&KVFay{5@eRN7NjH;~i*6EzjdX&V>Uk z&e1dNNU!?HHy+q5?PzK@qNbQTs`(BUREvf!3!dbxxex{+Hu4jCC+x=&J`9?a1d0FV z9dl7?ND9z9H?$o2X^p8Yyry=WlXgHz)7uR#d%j$3+_8Pj5MglmjK|1sb4F;)D_2vO zc(G7fUDY)7yPovW&}YSQ&Uz{uYUbR%OdIfz??SBvNF;eIkw^^=%O5=CyTz?LlCv8c zfUx!Pb4`=NAP-|@ldzaAXxBxgjNe|wN9shuW(1b$AmeO+=QtYUedK|8z-G0H6pwXt-f|_o2)yO#)MWC-^8`o(CI#l; zcp20`=x&$;ZqDM3=P$uYkHsrc&gW-QI_`vPLcgIa5XXXdyJKInSD+(T7|Z#~yxG9G zvi8Cm)IGW_~nRPHu2O{1) zP3g-ED{KIxU^+veYA`Noq9D114+u`8E2Yf3w?B+4-qURUJ2yng*@8p&)wXyc5!M;*SmA*$@&C32;X`9tHc1(Xx6yz z*3t_WI=xp=Mh~1F%+Fkh`GHQ565xyfLdlqfWP~?kf$JcF0Prw{xKJx zM%-B(g`eQe2gcbT=BOo`n@2@iu}3>MATKhaWDZ*ekHLRPp{D;A!CXFPD!Vb8QgN#rdN+IZ9cru*<76SmiMH{NL? z2p-?NZTxs9V>}ttzrX)?IuXWztUxrEmGtKG%mhq2@sUIC!Kz9dx+-mTxWwi#zGn_p zZno=`afd@{;0oG-lL0}nXV?fi7sx+B_62fYG!hiD4(Nw7c+{EV4M@6S6SUq8W~Z`Y z)aVTuJY5z_Y5B8(m^N|nFHsI%T;q-dr`DYY0;2BQFko*=+vT8!4 zsDZ!QfOOf5`Jdw_%aPZ!gOnbZAzRgVn~v!Xg+&lWR69S1U^L7DG{8mVAkzs3{%HKw zMLZ8bgu&2{EgeDj7ZPkYdYxhA4yGLRR4w>J6@pt;Dq;WwZw?d_4E#1@ z{=qR--vb7C_-6wAS_3&d=MJHrRLOq6GzIWZ0SCg20! zh~oWqK0n6Xv}fX*>uMJiHEt-o*1vW)e$L)=WHOo?8ha{cb&NiX@1I!v;4kLQ!3YQ2 zfan?X9QEBJzdk*!t>RpY>k$9A#nYYiox>j8oLmNb0Jl(J0dNwZ9B3cl^A=cGfv5az z1B72iknNq@8_(>YOZNL2&>{G|P*V(iN-1!TfKWn6k5d~$LHdy>eCjV;XnJ(RF(ah+ zc}3>X6TqwY@l|lp3v(yX;=b!+WB+a#eV+D&`Od@IMA-4Ma2mKtP}TSJ;jV3qsndiB zfB~YIBOI;}1^zjyTjBW+n2$UT|0`9q&1db|Uypijw4qG5*id|adP?s!7~RY?_l{@C z-uu6TwTKQ?{Y3uk8B=y#j_UWJgfW>d~=!v#bLA>``N4w)9{^L&nTdBRtL&id}&2?8C6Qox1WVEAgg$pk3dy;6YQFc zdhgOnR=sbn8S}nJR#0cudw*^hV+`8_y0e1Z!X?O$kWSMIcAQ@1#JoInV>eLGW&_+o z-Wfr#54;F(nUnu;$t=@qwNNugR#-DOJnHmDRH7c}UNUo=vc;xFC`-MNmO2DOe~*UQ zn`W+Wo1s5R)x&&fP;mM6QE6&Y{TNG=@NVay9Hlr(L(S6|<*0f1&ScRqHK6j$LKD=FX1}UAMn>eM5ECrh?(r zLvMYLzmu2IEl*=x%h7SctV;!M>$KRfVOw!YeyhOxC9N`@V- zS}#!SJw|XfL%&|NaYRNtQbQ!`&HmxDV%8T|E6JJ00BlDg=3++tX|U`?FgM56u(o_* zz5oRbGLrWeN$H~&Y_>{#^yK|pRIDZCW$8!DCUmZOwKP3<`Q?fGttc&JYHs+^9Ogb09N6r!CDgnKfKA@3)aolra^Mi%cZI!3bUlJc=E*$0^J$!y#RB}c~e&wPu zLbvLQp5pxD6IX(L{?)^=;~l#EA=8%U(=x@7Sb}!A!GXKzA(AA{BATpM@wPsE4p&2IEB!N@~duN2( zM6hbXPKW!#RK+KA(d3@$H z^DU#?+o|8Dz-EYsWNZOOUSk3#7aDUM-XzPxb4hC^$=>na$2edVZOR0i(bbM*LzgG<*YNRI7&zHsK3zb%{vQ^VQ* z1Ub>$Ft-L5v*Y9+p*27P*h8O4zw3)ibGndCx8bh&NRJ4=NoBPgibjC&dx2-m@MMyx z#~VQQ{o}i24!7?}nEU0x+{EH0F*a=?iaz0?m-zdxk{z?bmn9NN=vGlfB+$6^Tsro6 z1H9Xlh#tF*zFo7v__7LUfZ)|1{7g-bvI#d1oEz&ZWv}2- z1#hSMR-dSzaA6N!x=L&+wsB5RwNx{4T`_A!Vai4qbJwkL7V0KmovkAaVeK;D$A^%o zCy`N*R=gDEWHg~*5M98R)I&3Ts=#1jWUR7zDX?X2saa`IR}kGb6=w~1pJ>4mH2PyI z$=ee?DgwDr;(t&l1@FD(^d&F#|AW(o4BA3V#UaXO8KU)C$Ct61b3lfyuG_i_q6PN6 zke@Q=xipYu^mE+X#zRJ*%nzlTi~-F5!H!`J*aIt8t*%4RzWPH(pFF!7Y=Rbe_CM_y zK?_c6AAzSW^jmF&Cbi~*Y9)F7i>x=SEu}7zFBsqd1*}ElDxcah5KwVM)UH!_<0*6( z<6S3FHV6e*$T5)I{&(n0+=KGDy*lCTj2?{VVih*v3=0vX*LP+c(%7_m8al$!(j2;o zO`&#?=lg#F8d?C)bABsPAjF2D7nra~l%qLoUc;yQ5UgWNNM z`?HYh=WK6*^pltc=g$l5QFEK}#8T?^7W{_&8cEUp(+ykjF68ZzwK;Cj#IPvGVE-v+ zvOY)gj8T1;v!!j#n7?Xr1i{kSpQ0=+@Ci3}EJ+vJ;@Jddg+lPV%OF>63Lj`*cM`7~ zatK7nL6{zT^y-SN1Z8pho3B2aF%da_|4=QqCv@y|+&91D@$ZoAQ)B+XmkyoT_B%d& z5Pv7rwU{y;eB+uv#DLBrFdhLI`5NDkV-%3h)aIQl@O}hGj-J3z8no#qpLLSG;k7GJNL|ezjsN z`W0SbY|T8uH;X}hAgDuP5-h%i&(3Eb z%mZSQ!i96nd;%Ai$Ya-l->Hb+0}cNJ^hkUh4j&(45{!lWz3cbfSq<)+AQ&?H*GYz- z&_Mr={^wjBHt0`~84Rd#A&E(FkrzhrjTGO;?DhtKopCws3tgw-D-s~%hTk3-fz)mL zlJdR}!?<(km+zSpf&M0YMuL8}9JS$%_}c2xuxT$8u$WZYvx^}MBb|@4;KvrKNj{#@ zf$;*O!^v1i$Gb0!fZ6{H3S+o@Kb*DVMRp;u04DG3S58qwY5S0^w#U z8ova6PcTDYV5d-P`%GaOlJ%Fbqo@gUz_|l%5!ogZDr&+6FY(w%kouRR3N-u_H~Lr(_$|jhgra|*GVO8a7r1xn%BL@2 zPHI^X-WwXzwxq7e(*YST9bfEWMOrMJ=RQ(oDn~Q&0oH?p0fBA$3cyDcC zR}Ji$=b<9@JjmI=lBjO z2nf#T-H9XoA_*)|4?tkCPyk_J$y1waWLv{q;k)@(cnx;w0Sf2WS{D5Ze@#9O~VH1cFi$|(9D{ACmSIbS4z z8#m)h2?Wc?xg&_liXi^r2p>SsiL8`>bNN5y)I?T<=0#TCaE{~;7m=|Nh=O#tz%89S zNZqJDIQ>NWX9%4}&msjp5@Msz2I~W+ zf_#1e&q5Lh;t&jJ{RWXjUb91W+=H{B_)Gi~`&REP3Ob|p>}ALoK(a^hlXs{-Jd=*< zJ00qJ8X3^sy0?ITD42`W-9(}wMXK*PUc3c`l~JyI6rxXwen<8Q;dtn+I>2i*90Ra3 zj8JZ7!J_lQ9(b7-ilxy56l#YKaqM!uFC5l}Dg(aK0QGMNIRAnnA6KRG7e?c4~ z1aG;FhvV(gqy9X~yofr0MT^;C=q7fe_EPh47&^h9+f|t34$Q&FB49X~;SM``5XOnEI0#@FBsr`t`DII@RrDhumRsW$7NjF*XBA=aTyL# zRWS)@&-CSrx5w`>bv|$otyjxavJdjZiQ<*Bm^F0wNFQC-H3{r~;Kc|Dl@}ca2J#R6-blvJeg0mo4UkW)}J8=AhrMs2I5^-Os>XUe7(%LDQa9NzC~!O z^z=Ls8<)HS*iGnCnd_K9d36HdJq!Gqb}rY?#TUSQCQ6d{GID|CO*MMr3!W(1rF=Sm zsMU@f8w|$<`7!-J|J-}^g2|UdL#TT8Wr0Pu8HX1Ws9(7C@qEIMa0Au}#29Xo`JUad zuc+R%EX&Q%Ct!(V_byj5A-oN2%=+PZP{x4vQR_kZBjV#Tq!xk5BLsVr8!60wobei8 zJUA_!hj2H7$PBJz-=NO%_Dz~O2DK6#wsQ^?wRm>waA%LJycIdJIj`{oszbKvl} zR$K$;Yz3QvSi=Wg4`ehEJ4$`o|1zTZ}s4Z`0RIU4MlxiBsYe?df@G-**%42Zfn$Ir+sAac{b z=<>#{M&rkFaQMO+4X}nTfrIFxL1FY?K|H1be~)h#x{Z#_XitpVu=3_-ReJux;d9dy zRz?nz?!XdDP0`sExr zONt}NnIeS@ki%WzPeYtru2Dad23$}WCf4H!hv@?SdDGwn(%)KwY-X|HU_eR85q*1sUoFQf+Jy%@`9g0qfKQU$?&5$`h zwQHC|*a0cwGaV57+J=6_eJFS_Qh_se$DYUxB3U=k1^fhoq9uEF16o`GbASyWWchEZ~2x1h)FeJh=*k=V_R?%K;f zzkZO?zXoei+&#r0@K^1)UVQNWMXvRj_>8#hqk$oU-$Gc83Cj8-!$~(p zg1bFJbR9GP$R4T_iB#21_5A~eY9Q5cT^BsRy5{{MzX%-XK(aif0~Yr#GpQjdLE_$H$4A;omjb>pLw=p#p1bT1 z1sakcSFw+Bq=vCWRr7PupPdzTk)b7xNog0NWTWwK567kCx-6)`SCLV5QYNZg`Hf7f zu1GWPC{i|}pra%`!Nxo{5B2B!NpVDgjD1_V6l({{$Qh(UPSP5D0#JqW8YHm%NraCR z2i)IWR~!&U(B4Px-f?aNm#QJP#ZV4tJ%7g5Ewd*1ySVt*&)U3pvZ<1>txQAP%~4BL zE%N5X!t^0x`ym;HlQN>?&6TuN&Fm6T^~So&sZ~2>bau|zUNyDUPt`6LUv(22>#7Y! zhDDi8wbN&eYtAf!j{G8-7;;c>mVSUoKft2_kucnD{~L{bi3{HX!LM%CW9*;nt{(xU zk&Dj%GOM;TqvX(c-yIl}NiF^7^v`f+iWFceJpB2Ew_mJ0*?aZCQoxBTtV3!_z{ar~ zJS&Ng^@qda-bflqikbme@)wkX!vvrC;HW+mVJ+?JNb^z4Q5CC>N~8Uw)CCFg>=R^( z664~0HI)$lnTk`_agEFMvXl9!!7ivMnUjv?mekxj9A>SOntDIgUMCU@m%8a1B@;SA z@WyKe2I4V%S4SIbZhi38KH344H*zngC3qoy{XX8aJ|j(tg%(842qneF`f4iT8#UR< zcvV`Vnv<%kqgqiKodCOJ0>}=W6}2^#Q`7FHkv%v^$YfDuhY{hhLw+wZpc@aM8!$GJ zo)})=Ywb zX1*awF3}vGos9&;D6J?OFUTEU*IKptvlU&fTdGY za8Gp_y~NtUn82chL&L+#?{EY<2EQXe_Fe@~U11{#j;~?AhJ*X{hilTjupnX!&YAu? zoo&e&_WSR{(y8Wj@*U<6W85R)?_N^p(%Ao$eg|`a%}2NePD$=~5ZVCnAif26;s<7> z-}z{zk1t;~v$$!rgRgFA!{~sJ{W&?PEtg?^)M(UKwJ0~uOV(K8<6x)n>+Y3LPmkbn zD+SyJ!a7h#WXDTXD5)91?0|$Fz@tCnUwx}XB=Nup6(V<;!1TRo+4%BhC2cLG5$R9U z-L+$sv^AASWIQ21qN};-SJRz!L-8Io&R5Tt08828ete%GPNL3m;*R{l9;Twh!ii|c zx$Jl)k`5s?cnrArL~@W`H=Fm{2oucZhUYLSv(sL(MLUnDo z*jyK(u`GgP1%l+IZbHLUj=q2`m<*UdW)KI2nrt{{kH^Q)<|<+Q-f*?jjT9flRY{pDJm%^Z(*be)3X@#i5>K zVrHP@Qfo4x_o@c6++(q9v5F4tz*?lfv{8@?RUSsjR8(&cyZpF6RjDU@hHx z_cPElF`URBN?|<6A2pCa#sfD4c_fR;%QNK4i=?k;d3iZ$?Z#PKQbtYFtS>t34)#54xv7WB8&2;zR|A`@eVF>?FW}KlW!POnvMX{N^zFP1L!T*6X zRBLZe9$eutI+#C4JvhgFz+bRJtei8+zCB6(69~Car8A&%P&#vvatTVg*F}&{BG3b^ zL-Hlw88rdcO75YBN0fE7RYv6C_t_FHpge8W5!qhAx7{LE0xehynb|M z&Fa-PnecAUu$UtMe3cc&E`iWNiIda}U>|62blLh#V}c^3BedfTHi<3FWz>lZnICrc z2epC}#sVzLK$AeCa$Ab%5*?7Xe2|qBxANdBZzmWMO8HbrLUr6gP?k}iT)*YfOe5d0 zL}yJkMeVG@l@*C;|72{M8lTo&zvftjp`R?lPD?{YNjL0fQDR16oaTlpu4%GTGd@heej3^3`z`XO5h*dd%pOl3e^luBMu;D0Gi+$f&p~J=)ex*Gfj} z!$=JRM9TRNvAm5jNX#HFA&f*AjUy`wDUH)-LK0%}4>j2-ctT2c4Zf$Y?HXq!bft5n zK_U}dqW3CMNQ`@(tFCeCmOyQdK^uYwe2s&(z~1^)KYd^svK;6wo^`!G{GJ)-qm@xL z@xcE2YGtw7s9a>0>!Y2%0<0ddE@cPR(Zi6bTy3$+N9J^N%sE261@4h~gZgEKzhqll z<~*i;hu@HMBk@IYH&qD=>X$D}z4L-2h~GXo!g15-`>L#WVc z*iX5R!r&Wb>a=dy))1j1d}dhCL%p*+bu=`!rOX7*Re<00ZLP|vMygZ~`33Aj7xqAE zMF}D4iD{mFX?wAaB296kjaD2~mtuG~8|mXJs9qtjQaC5IR>rr{bo zl#;K%x=BEi+N$*2o!JuY_*xxGV6GfYYZ`^fjF67GnMjqQtVa=hWkmMQTn5VUdZ#6L zD>oo-?`j|X3jZb?lE6&iZ50Ofbxn2gX&-_NjfS{MsFW#FJIeg}sC#nRjNm<%ygk6# z&zzQ!s1dC;pfFU>hmC^i1t=W^4a#hJ`zkQ)uhfFuUyVusE7esi7TMu?n|AD5w$2-HsX!1tkAD(rhoQAKMgIopx2rU9&JMI@Zu_k#{4U>Xnb5zrUhO#(ro z&luQv_5Gb@KwW3QOo%nsb)_Ds8L&gB5edXoh_ka|9O`n@HUk^M&%L)-4ol!(meL23*5g{ZmPmXPM3_R?}Wk7jl8r1gsTI+fraG!i)R!Pn4wZ9_# zmAR&yz|=nvNw9id$UE6#)J|v|!*3DMtqM;O?5}P({Uy78uhiI{)dhqD(#N2h* zO}l$PBa)1X8wyQVy+KDs!oETU<`CBf3tTQ03FN%l36u)WK0pZacN1(#>y`mM9Xh4; zSX)_4Y<^}|x2JW@>irG19kHoX3wmVHV_LIP(bbdl7FDQbW-+qRFgpou9MduHaBFeZ z!ci;7X602D1KwBl|4l#TaKhVs)(U_OT@jQ~^6X_#-X$)-ht9DQ{nVo9<$3(VwjO1m zU~i{Ds6)_>!@s4OoST;doUNoTiu={leIqhFKP(qHbvyaEnVIR`2#c71*(XXQfL_;w z@LG|)B4-VQUpROW04Qf}^KgU0g11@mfkU}*5}LizUt0~;tvJwF+t_lfZS1IY0)2ia zKDaoqH9Ivnb@JGxIGM~uH@LoI{*jY&+w)K|fxq`8GF_gxu%h_0mf~@Fkm`cHv;q9@ z0DcQ1%{i-=V1OhY!1@O|1R@VTOaBwVltpA>sEF)dptY)?%mAn+a-CkzGgPt`}o+R z&4pnhY`H8{7D{!5gjG*Z25TGQD>8VeL^!<{C_h*M*nwDKTq{lfoH-H)gb&z8oXtZ* z9PmXbkE1?B&OuHKd|z9!^(O}t?q(;`3HSB6)?SvWk?$Pt@nT%ZuBPJ$XC7GP;T-<$ zg4z*9Qv#hmar2~%%!&0Gnf3SQ#Vj`%GQ=P+B(1Y@TvhpEI>b&ABd{8t*Z!rqrA3h< z9g;C~ZLHKcp?gtYSaw=)=J>XYA+aWKg)*~sT2^LLGh0~>b;s6DnHetD*3dJH-0OyW zLFPPV4R|nMPjDOk7t9inNgp9-SK`6sX5u4RS?NYr*%RZVMrNktZ5dg4qcXC(qt%#k zn~?sGV44Jp}(ewmYsq~YpGx)JgJm48>Y6oKlhP0CY z$A%D3yF_}Sk9}=@0G= zFfIolHUnk8?~+;1q%63w_iIK9%JH;9hMDAK$ypLH0dqjkju}U9CU?o@{yOMB&kt0@ z>FIy}l^kr2X#h%&vc_c`NzXJ%&ULrf&P?yh$kI-PA5AjTk7Q)o+Gk`%qzEz!$GIm@ zKV_RmHbQAEElVxI&4j={`59O`G_k4*KVaYSuyXVc`vm(?ehy?)|9^V_Kgr!sNBw`1 zI}s{Ix_)wErxfOc{Cp4cQ;Vxo9}J!laXFx`1{J83e&5)9?09oyWApLj%?(QuGn$$* zk`ppoTQcI&*C*$-x6eCyYW|WX^LI}hT~=1mI-`8TgfgNpKz4-!j3SbAm+QxWV`T$A z2}Hu1|Dq-Hva|4x%&a`3E4{4I|4^2=G%O?}j7bU!vy=X(wj?~~27Aeby_oYIBnBi5 z@Hml~L~p=1;;?XvOMVWVx|TAT8MrGWqjda^qfHG+_0;ML6c;-t1MiB6ubwq>SV~sQ zxXpM*h%6LsZC*6*#A#$Q-dH0kr?-K+kx@6Su(W8-^y12cK%2vXHl1M)ps_ePZZ9Tz zwSU71NOy7}m~r+LizU?diqb!_ve;`G8M}66Wc-%HEW3G`wh?>zh$q(W#Q*R*Ll&B) z;jRXyC(u_E&h`PE?Ld436b5IGk)tJlBp_o3qM5vs;9|byS8}}oZycf@%&u6o39@3L zarPQYIzxQ@Ymm-?O`8ua7~4HPU)d)#)<;9A?J{R%bm;+P?Q#IAFNyU}Ny)yNt*PW# z?%=$%z|qDgaOrHB$B-e}i?cl9bUX~KBI0fRbfNA6DNF_1NrhR<|DG3a7Qn3J|S2zuy6+5ZOUze|2o zLQ%}$2c$oeso(&DDGsMYl#2%w>aCvsTEpEV*Z8%Hz3T8pq@3iXk^KCrimhsH5>iU0 zvpv-)#ER{$W2sw2dP*R4!X`pRO?W7*=LPGLd%uuN;CxPgJvdeHwD`gddolgN?Q=## zi7wCZKoxMa5q3e`s}vidce9F}o4=)&gS~)Kks7I*Mo1h~T77h_bN|WBEvck}?ack0 zg<9GnMs(Sj+}zhWbgqkrGGg7`tnGByE_VsJn5#Y1%7cP{n@cF1Mk^8rxM*uSZ(B)C zm4%WsNdR8(gS~=3HK>Qclln*vK^Yg17S2I6^yW4WSR%d_O|-sW8h)2(EtH-*qCYGN zze~-^LMm)#Rx(megv)p9R(lDplaO*sb|x5a895-H!Lo-0-a8_kp%+sih~%Lf%6IN4 zX%2-wLPwv?u&-#46Tu(hkoT84*+6tM-){z4D}e>Yof+92_^e!j^TThMU?24~e9kF$ zSar;pkq(|}6+!A!{H3y;b5-j}(1 z-<2dcs*C*%B}5y5_w`eOTm$B1311{I->YF1LYpSDJf!%%icO13;V1F?2$ z8+~f9_YN^vh-J;)QsHv!yq!xB#JODqJWFje&08IxXX59V=9lAd;iREsY?{9+ZnS~F zU#4HCzony=t|9W$jr^w|UL4)A?>;t4EtZKlmC@-@Z*b%&D&wy%ExnxsaH!n&O65^bzF4b^1WIM5vMm1kjIz2`D!3h}<{*sekk2 zVDE}?k|Rgxb9CN?*z(>vg*5zE$V@0A`ijg|A;^ZDH)MpNT%71-(o(&m_iOZ>hD4^3 z{pPhmVrSR;Idz&1f#v!AG3Q`?MdQx~KO1tNR}6d>?BPDof&sLGfB!Rqi69+p0K$w!X+qA~5OM0zHfFZCkT?E7V6iY*~q~;PX(|7>NAi3h{%& zLS#`$b>f@Hzx?7jq~lypfBp4o{GJM853=oOO;{M3B$LVaO8vm?W%l6S)^nfd4&V~* zC}xpL4iOlhAS1mX@nT@8FaKcR&7lOEWvjUyarOSeXB}qywdaf1I9N@#T&#%Zs0Vwh zqXml<6$@$Wz87kOLih;@nG?3Qz3x1&6yI{|%^zH!#|>Da1UG>HUGVSZ?mem3;9B63 zNP`l0iTndbAhl1!%~tR?$z674Lm{oNHG@6gq@^b)&}9PF6|mO|3MjXNliIyIbqgt4 z$-IH8sIe2!`)0sd=!lr4B~|B5%Mvl zLT7-i!0{Zw%3u$4!5+`*vEJTetGo_j@57$=yuH8oI&wrX;m{#DkpZ~@LV(zcdglz# z&gUFH7XAlq=yA1!q$=nm+7M78D_S6efWyC0gc>x6x~5J|WM{+8ROJ4j^l+EbWnUDs zCx{Fqcz(#kglJ;xd&8@8iDVV>9K^jo1B?NXH_XGp-UC)@=rvYUvSQ)_3(RZsU;lyT zD5+o?4Szpsf*B=Xdu>$JDKRxiWr!8FdX^Z56;;$URN3nxNxu)AGt@W{Pjlbi_lg4e?G(G_Tpqz|SYX&@&iZ$%Q2uFoU@ z#=PliI`&lBR38{Lsmc54(Wai&t%sjVTk3;?CN_ILJ<`&H@0dGORyx4jJ}Vr|&BfH} zO@&FiS9xi4RX3?{)5f9{?W;wEaEh*Krxb0R|^eq)g6w~BJrPxhNM$q$M_0zYRRg?|^M?j2ydk#8aL6|6oY7W+C)U0CXWj8Y(db<3gpnrjj<*GPoVcCxZbvim zq;~dVyBIB4W}iN1xvXjYuT2#dO~2MPMJ$__s;31q8sz@y{-cUPf{9QMtV6J-#3j3U zj_`oGV8tMYO%mGM3)v*bO3-a}zpnya6pU0=e%~P$3(A#Mji2-tl6i(g{^47Q8(9#o z&Bw>YoMIe=#~b>*5?I6%cw5z=Z>PCx!PS;HZn6zTR@G$ zv`%zgwWpnx>*z%c;no}O97Kk{0V#WVQ*?WLBb-fS3oI4UWfe^xm5JK21Bw_E3 z3>g9{qJV&?Ac~3#;=qA>Z*lK!-K$ouqg7kAt+Tbu-PYQzlH>QDdlS_D`v1P?t51;| z;hy)rd!6_2kr*dl`h(#P$d)tg^pkOI=N2ah{~Cmr9UeVp*@*rxTs^`=L;S*`LVSI- z(UCr?+Rkak71}^_;X=pUGQ4lY=TjID^t9K2z1v2`Z+z6hx+&Vm8Pu1vRNQOku+(CF zt?QrS85KQwJ_y6<^bPPWWITj4P?~smpmKovpk?LcB1uw^Ai&W#rg-j=k00ym79dXQ zUEXM!v*pM6HO|(S9vP$PjIsYD;_p7&bnJ3vTYLW8o!>9BMrFFeKOSxJfr&Py`SXQbhXFd86(e9Q?72r&uA$iNqv(WVboV9@SA*H1qgQnRUV-_p#O zRk`DehG&OIqI1{rUynZAGGS~`T3T^)dXgsG zD|ARic6LOJ+{7y|p>Ord&}I0S!V@v!c>aU|W1ETq6-HqIYXRUTn&%*JVn7A)cXku( zkTd)IC!8lp`uqSt z6=BuW-)sA#R4XeR|A1cvg3(Fw5gAj@XsyDN2DU}}Zx~=BQJ8v}dT-ey3JtVMjx0Jl z(#_q8gArHJ9qd5@Bg^GR_2LSQ15g1V5bKdE5eO*(Xt;P0YLFb5pj0Uyo$zQ!cbxA` z2#)iV`8yAF4o!*)avSG{OVc9fqy&bYHtQAT`*3>Znn`26jY@9!nC4NxJf`y_Da1gI z4o+#Ife{wy+?A~z$4ry~i8H*FzJ-2C=#R*O*|9D`gW{yEo8!#ezWN?jc}rp8Vkgdg9#iw@(AyZ5Nu`1{YG+mX3~+>!g|B!as7 zm@3!pG#jd03+uosu{VEEhaj&Z)@vGf*qTtSFsK*m5a<(pdk(7anQPU;eq8Ssl&c#` z-oJcx6>xQnhAHEdOLe|3t42<{U<1k4QNVKZks;7gOwPo=wbtA3swPp+Kkvvs6j3%3r)>9-)KL?HAQgAPPO zxLOPbY!fNqQ_A$WBk?1bs0h&=`VE~XPhO&LvW=Z*q{7uI zBRpr&fLJvMCDE7K*tuKO;7k{cs zTX+FoxCvQq;jM3G%$qk8|FO4u8$PtFZ5QB74YCJEt-0KfOd{gF2TogB%V}T(Si}Z0 zF8p^Im5k}c|I|1tWI-ii%C%YIq4nnd685VajRRA%hSN3F>!Eo2UVqyFC;N{Vw4oT? z?6rL@J&-vXmme6GlBKt^81`YqTQS&&p3&ah3`sX~7KFz5^_NR~1l|v58uQid$>U#y zrp~Vn^DoZta}izm3jaL_uUUP5DiwaaedhdG_^%x;+k2%C!XKBWlA15!hbCAH{JL&_ z0E~g$7*sB2CwMIW+nAA`BKo%J!s^7}*i=8~dgsu@*g&Uxr}GWN=PteV){w1fsGBm% zb*$^q6)~&Mg0l4u#^f+P(ARX@@or2lINVJUbmn54C_AsYRXLA&##+bY#FnK@ITO! zz6|elh6fn@$2(2L8-!vF^TgSCkXBWM~AK~*0nzkbEtW=whHr@{_Wm%a=?+ z90^mv)r367h+U9a+d5Mb154kGxelpGe-@4Zg z@{vdiSsT#4&YK4oBs%-zpP!@Sa)~CNxLE@WlN{~tKgVO;6NiB|?t?ds?LYdUu8WRY z9X^|=-?0NmRiO1c&$;+61R!M1Qsy<_7d&9Yjv?>+uCWCS!_KATN)nRJ;=O&~j@P~F zZ`R|=ZdBWOx7Cm6kz^+liK@m?eV%W>&Fy;{irRZy6wjml<))MgLV9@D9LtHrTk~?m z)KQ^;c@7RZo0Nt5!r41GHvuxqQJK_i`D7NcK*S{vLg4tZX=OEgKJMA` z<2|)yE9WB<@%AXsv2n4XF7bow;#@*w;-+}T>=PrC`76=BLlYNFnKFOUA;e5?qkA!{ z%CF#U31O-2vz|YnGbuGJ0Y%-c-pux*+erS0GRk}NHS-y}7x+)bK}H6==-nqNFdbw& zU|NB}7lo8i_Xu$k$`Qt7KC`OS{d9KB$<6Ct-03C8ox4i>Bhy2JGo1$_5pqO1__Ns5 zu?KS8BsRYu>YYl5mkiWZVC6ifJO0pT6qNuR-aoV>ywQ`E|Nn;qZN$W5!okA1%G zc-Pb9^|y;pnZe7%hb%)v@KWBzHf}s)dRmf8jHu)|#UDxt*O08KP9*^ABxw>uT4_r#w>%}cMKdZ$f7nJw%7I*p%1oSpeNE-L?TK#?9tF9An{ z$B943xfz6rYIu@@m#G(Oi9s6+3AZU#cJ#~r$9}V49H(%6tcbC{d# z<$ikz`2-GOA4S^_{;3I0+_GGO(7`~{F@<9W_Wt?UZ|cCb%}ZtYR>`ae zFVmIFm60qkOlRR;0gYCv0ulR<%mk}EzV0U&A^!8a<44y03g0|mcLe{OlfQUzK{l>f zlAn`ZfIhiDxzUoynq}kU`wu#rEx!HMqPgSZ`szAS*Eiy^!*sNVsIGebhGAoYPSLoK zegU{p@RDW(=iCWZq%f44*k3L#As!e2X3%x-+4vV=u<4g@oQ8&*=e`9ya1@y(Sb^^5hUg)PJ_g}PgX zt(^aGC~RiU~<-8T#p`LtBzU zVjyP&J$dX9b{yo44{|vi^1On};T+=li#(IwJ(9x-g9&YXV9d9$!gw!4;wc`rGQA;$ zn7&ccrb>uV%z1>?g?B&>0&c9Jg0#T@@(d^5y4!5Uw(jI?z1W>Uj_ERm^kNQx?i zZVO<2Xc^w-Z)fTr7B?z){8nU= zUw0LRNTAr(4*YxI#6Nwy=GvQ4zuUSvGXtnC*}AW-tQ;Jyt;DQC9`Nc*N>IZvU1<(* zdP$Fu54imw?S4+@p06671#R5(30R*t`tr?J0#kMntS=+EOeCVY+^kvzt(U-cd`+8E z@HzPHU z3RNf=Ml7dI6NMJ^&s}L@PAW%BAhy_pkxpYK$^%}9sVo_W?uJ=-fP?X)ZkTy`oZ;vJ zCl=Ui@b8Y0J1qoy=&=p#2qk|m0j3U%gVKR46v3sv{B{T>$Y%yZh=~Hz_cC(kgb1v} z4t|HXF6=cwV;iwmwT>=#c94q1f;e*@`mO?hCkQvQvK8ruNX1e%($vPz2DT}-Q};AB zW1PAi{H)BRrj~XBOKmdsdyS=uo0FA<4K%;&>u8&8>*UxY+16bAi9+{UD81<;F^%af z`NPN7IH64UrSummONp7B@CH9y{l?}$}~OC*3<<5!EEso#f$KBQH+&y;AE-L6uIhl;%}HO z3LrCnZWRk3`}(Ry#-_+zP;8YH$ZYUt{hWj>LNY6_*VjaF{i&Ex+RM|-muY%Ey88nq zLWp%T_hAC;%{(OFo*LwE2}kF199<22B{LgI{^b9XGnwY?NJ7p3DN)UF^e(BQtH1^1 z>f1w||CaVAFpyjmeix!<7%S(%vTtDGu%cUp`edUL`iCmRc`;K^T^^dD3D8EDO8mT-AakLlr()cb)&=&9EZ=g1f<=y&>-|xL<_k@ktz3@HA z3|G_9OQf1dhZnF^6w!4QKLZ6U*0+s8Czq)@Yg`0Mnb@vf;`}P~nj`@xoq1|X{ug{HqbCan6uYd*rN_iH{KuXj+s z@6~*kzFtFop=FRyxC#ER4_|R3yun9mdO-l!7qnJ)h-c@5;FtyUy8%KV+~bnb5Y{m_ zO&sIWa#3=4p|R95X5fP0qo1zmmAic7{na_~QxlABq;Nqaz2k$%KKl>TI~+sitl3xY zCqFaZ#>%1L%$d3YoexfZI%VkAV;`cLK%HBVug44zH0Pg7S6{$hX(KOO#2jNWXmL4z z9t2?2JH%#sbF4qFj=TUOAQ5-+N$x?DdGTC~#YO6z`US2A8Z*aI5~}CUTzcc{%o)y6 zkph$$IjQq{%SOD=D?C~$_g45Isc%5)tz}{LimrF{@i)DV@k%>)QlZO`KE-A@{o9BBX|6A55_3=O|^mE zV+AHaZ?5BuTO2eZPe@)T5Qw@7uGa&GS!R?0oy^$8fK0U_y(U2&UA978wteq+OZ%1X zIB-+q(($J(_&esr;}dinjc zSC|*$zmfTNjas|Q=Gz|lkK&5N>@zzEj}zX6dAlFNx$}5}Eda{^C&!$GHF@Ji#F*FH z2FOWbgf~UqEJ6Pg;^f*H*iySNv#`0NvneGpII=ct$Qkg*g1km`wU^gNsPgi+%~_J# ze+)hm6q>H}@=I0H=}xL}dGG+Omm)mgSr!@_)5p&>M+&kzCoZG4FgGnAs$_a`hN}Y4 zvk;pC*aU9q2Mc7Mfkf%8sZwAhu_afF>A9ARa=Ds;UakOy$yN;yuI(9g~y)FLRrKHS_& zq~}qlAK;zu1=YuIZyTlF}Vev z?q%uf=I)tXmTW0@aQ1Lh=jLlvY{!L$_$2C1WLlRtQ)6jQU(JeNwy*EW<;#Qe12y&w zqDBuLI;FT0zfnsZ3kL@F&}s@!N5+6&I0d>ZknMsR5mc2{P(&Mn~!|^ z`~osxKf)7P{}>?IGDh@=fK`d z4K(1E`|LjRF+ym^Q43x!BI7aB|5I z>z57UqzK_f@+G6B`IJdhMIPPk7nkB_tH9s5d7pI~~ViMe}aerlM~Q0 z%sIAw8vY}sucK{@AEgyqgs+sEIXZzYSAL;Edu{E_g*M8J^=SH9d@{MxCc?#!iV<3F zMmrMhA}j<#Q!D$GuU#T!z^w!Z50JMFfGd)303IMvz!w8f^g$X=5WtH8cZ7}klq83$ z4GwAJGpa2|ZJE}i+%+azh{D8)Q7)Cv>pL2p&6bJdqZO7e?r!qrgdkgYa~nIPcFFy& zBzXp$Ba=8E|6_x~Qj7A0ue;Ailj` zYjP|^q(ud8T(^26h~w3h1bSIWamGMCKpm%4|4%hVd+CiYV|}nzIV3G3t7z1cBNZtg zv^e0#@rScTJ*SuY2YCcV*?CR~2#oi#oc}O#ZFTR73&zwgvy$5xo5$A83k?pA^mTO( z4vwfvi;0T%3Q36uMHUcRRXd_7-bouPGM2C3J1MJgxM^rf=`2fAN12_JLat#MK>=>& z+7fxig7&GS)ALr&8&MVD5#7(uGThSF*)-hT#7=k0ifA|DBNLxT26PZO+~epn8lL}# zTpMW`g+^h{W#Dqy)?s2eZ`y5=q4xGx_d%?{{9XNrZ=^`=)~DA z)BHod%^b9|7E!l)(u30u?>x8ESKt;I~Wjdc=?#(mOS9jSmyBecyNUW8`Tx)fDiV9(q`MyWUenR$85|y#y|JOM0t{Tu zf$+gwuYmUqIOgCZCBhj&qz(>z3!DVaCRY`#b7{_|1?xgQO7hpnNnP7}y9Y!#h|(qg z+M>%NLJ}_=zL^x?j~=hE@EJ5>O;Na)%CC=?t1`a#d~=ahB25iQ3?3dInLX_D#U19> z24Ceq&_zrtK!h@S^Qm7H(lMl2+?!1exX5uyV<%gRp{Z)Op zOddrKNvWK9``D@4s>NR)If;*#4?nx*T>rTAFHXVBjhcZ6dcj(boQ%N0D_%1HP4Qk; z_|SZtq-eAId!ZdT#M{hXJ8M3boC;*tx%JT+ds4T%iOS&=`k)yF;FRMn(n|q6#o5ev zIEg#C1)der>xRlZqwrV&JqwR&BcTi0#gBAB4_KX5;WxDN$97qDtfGVtD43&Lg-pgH zo8=+t{evbbCE}Dnt1^8X@pqFyLWk?a(zntINH6mK$O(W!@lHRLfvLHG&!7?|B37g2 zd`@nrJNyiwBFcmh$MdH*HCl17n@a{eWTgwxOV?8LG5GBua-~j*l@_3PTWDlXe zb;OWCF&ViUXPhpyl%N|Y8^Vf(_O`KAqti6$rnzXFjYvvw6X>QMJb|Bin~t&-JNFCF z{Jp)mZl|fODK&~ZI?~qCt$$45HCNn4rP>30#CI=XAHk_g$R!CWmcx(U^MSD0=D&K| ziNmb7KnT2419{nk56<6sPtW?(gh-%Gj9E5oJ zr$-Ld#4C#F0DJ@E$JC;<4=jXYlhcXQ9AGXKYAR083#`qPSi`K;ET3BZbNOvYc71>? z>-=iK#dBAZcO$|Bi0C}F5^ziMP+We5*a32Xr=Io(#~!>UFhPL#cVMmbj;@?>beCw_ z&TDI8r4s8CilDNUjm6cwd{w**S`1y`nN5RW4+Ya34is)z=ZsZ zNE48I_QPH4HYV@oKmmU2{pJQUmpukGx_Ay6u!Lm1utAf+xd>u)K=dFb^R||#S2O&- z2moFVNZ`!5+PrxOf5o~!PDf7tI3z9EnhH;@oCt|7T!o@Lcxyg03Ox1QoTqq-mf zHT$OF#jXLG>Vi{9Qk>xxq+VTKa$sX^{T+I|Of#b25*PWz!Xc^o<&ZV-mKmFl8oKr% za?Vo$-iR)F0{(6&>0HxWatithNW$hFf#9?xuT8|B2BZ?A@=0iN|d+%kRwe)dZwd@cbXIl4Y~vb6<`4Y z2FO_cFYs00Zh&V%1^h)nHw(FA*Ds=vjV+zOwmbx{&m9#gRDWYPKwV)irc(A)grGi! zbz$^8C*__6!>TTxu|;P1%cHYD`3c_(w{*HPe^CGP7wv^6$mhV!Gf$8`@rNq$0H%W- z50w{RUe6d2zzDGjrubGQBhE*Z3e<3RfUCwRX#kOUwIuqLf}WZBn`NAdg^9U+fR)>U z!PRKoi;-p^=YqzwgG$@8)0?k-HM13;`l_R~Bz-U?zKXXCHUB7mjqTW7@olDc0~ddW ziiGG3ABhXXVU{B+`%TPB5q5oO{lR*4SG;fS$1}5{1wd~F=tJVCDBtsJIT#3y<-mM$ z0GyK?U^8Ao4AmoEpoxzlgV?-vk3-<3=H^KPkANlSQmOgmh@z;RsGQarOP2I2ogWxh zrVrH-GtP(e7nZba@3|>dBC)S^a7#eGF}r47N49lyN-GCfXAMZ|@ohH#lSJxh^DHoP z#KwSrdBujod_hj8!Hc4Sxc^@&2Jp>usJmDdDi4J7bp*$(9s8tHTO~ zkAK7mC)Tv0qp78-KRaCQtjHRKTz7*R?!qte1x^o{BPUJ|-M*>ULwRRD>^k{79a*?) z7)&y(S$)LWyJuqvbPw`*Q+5VB41B`J-OoF@Jn9qJAL44BJ>VJU!RV*)>Qm$-NC!Rv z4~R%Trx6Uy6bcha2ywtwl(0QKD0e2rNf4=O>6F;MaHzL;buuxtjCc?kd@9Jv-c&13 zc`?b-Nk*S{Vx_p&5v~BRE3z9C;LW^VKtXq-Ok`^>5GaF8q1BQZ!Wg^7f>T71x(%ZM zxVhf%f7LP-Fe6E!>KdaEQ5(eZ*~~QjaW)?1R}(>eTp~zg#Wtz81?%Jr1%$2{6zfe)QHfy2`F%0befBcRk94(`)=_KIUC|+WA5jX&=+g$W#NcW-lIbz;(z+oh3iqgX_By-RO4u5pR{t5T| zCr6_^py6?NmI3!xa(v4x3ys=KuHZr${rME|0c6C~(zX=OyYG>SXKfj$U&OZH8N=Z! zUPHpK@J5fXa+0GL$JMN#hl#bNtW?)m?P+6f1H}xjVv(;Le6Y22A%n2!C$xWR42S@7k5v z2^pb@OXxu0cLV&1Rp+xM-r)lIP8Qa^Dl?Ix^ZEA}^zV##zG$X=3?Dd?t zAL->Ev9xEbL2fs2G$+kH@5-f=i<o_%aI^ zX0ptziOM82HV-i05#^)%$Jo+T_ob(5iBFCLQW)btD!Gj*kFXMm7Gfgo&o6g|D|^*NI%4CTypV0&v*%j26#viS}?mVTQS_B z(OTwYY-SnxAX0l*>*Rr=gZnp04or17Ha54F+sg)hx;{6W%Br2w*(Y4Z3>a)HaE{qO zd5`V~(EAiCw-yt{9|l*YQht?%$VFvqYwsva{9@{wL^hAa#n5$W+{*Pq*U*4Mt?*3;3%)H3{j zxca8XQAQ;Mmif&e*?w}{Nx#q;j>e{z+WX;}uQU$s$sK-6n`hu>%j==*zx?kR)SV-3 z!!MDY2t4?msErYODYtaS2W`WtPZ^kI<{%JwM}vvG(4(a9d>7rP0Tivp`)9f8`CCxP z(di9Gr!1fo=|6#<4L*+1yKn!wSF%B}Q=lb$1@*-1D>1k0clQj!E+#5lu*Jnh9PX{2 z88LcTfuE#NEC;$-!AVirw3A1{7{4`rs~nS^Kknx_;e+7O!7_pl*tA>9jJqh2B7+z45D7W;*%|H^rFH_; zE39LNs^<`~m4~}X<h=s`T>VkyFR4FUl^i0owilu37${=hTR=>CXAZq&E(N39dg8m{{+D5wDZuZ<3di z0A&e-11Eq(O1OoDMyxy1e4vr$+WBS1CuFy~o^RW8W!c)FcGva`s4x?lxp`p^GgH@+ ze!b#drK@Y{X*7$!>axNwdb`H>dzEEuKD+zZL#G!`KA4GA9>x~B_yY%!!|JBC%Iu#& z2iM|4=12BRt}2nlL8$i;3@K@i*v632LwuD7Qa=#F@x08FkHkb|BV68G!~8gP_`=n{ z{5)(7tBSTYjfkBZHh%H7X=MZPOjj>uuCZ;7=H&b(L$duM{mc{6o7Y$7I^+I_TV zym#3ctAoIYw;|tw0MDdP6!1n8q2v#YHU^yPLv-$$3!MPR5F9}q0@y`Pn)oWI2Q4&l z4~h?^nLI^M>L(jQO>J$w!YSWALl$qVN_ASVv686idC|>t@XwK>lsUyKzX2y+HZ|wR z%Ei5%loEGV*jY9D{EX}9a5{KvT#UiA3CtiK;xa^fDtqz$`Fw_wK*#GglBOozbWphj z$oWJ+)0Ptzo$C`E_+eXic27mns9E^rT zL!1WzHV-HY)Z{pm1VaYO5*!g;)%Q+wyvo5!e!~tjS!uR*9`5o1`$qPjDU#v2gSvdp*HRC(0Y9>wf_n(GJiUv=|V_m~5vcgAY&>?bXH<7=qf0?(ts<1I2 zt0GP5oF?!Pg*Znp(x%Rt)1ZR+f7d+x@f=epI{+Kto{rPt-0?RMx4{WwKBoYYqZ_$% zPQM9t7||viJCY0>01LbeU&$7@i8De2)Xd!sucenyeVtU0oY6m_N2T|~V0*F6qH3Q~ z--TJ*=>gDG@J~J3O;1M{1$SgNK zZ_+DJnLwYjNu1bZZ^pXjnLt@IhHf)g#<^PCSV%P)c_l^3+1BlAkR5d)GN`LKATdHI zvZU7)B@R8Pus26T!3t*M= z!2ogGmE|O(02NcdB1u{&8ke2G-)-rYy!<3`+ftPDtoL3xAf_$C`y=}tV9fD8d;&Kt zA9o14pJ1Be^0A_;x+O5osukZIa|Q76400?z=+lPtAl>{AlasmZnZ6K7%m?8*x(DS~ zI%rfyMo+;6lY)T2DAZ=AOpOb36@pdpLt%`dwNITovfR#vs_{=w3^ZYN>%;sq;?-GB zzGB#l(KXoHPFN4(PGXyQMN8Cz9dU~Fa;E2Rk^lhW5LNM(DBW=BA+lq3dMYD*L)jix z?Xt%Fa9q=QPwQ=b}_0cBh2+WMo_=bRJH0#*6(EKVTq+$FCWt;hskhrP^$z5L03 zX5E|51fZ7D+AK(1L zyrDnh`X_AK&D(h5V=gN8xIn#3|KIE{V= zx+%>l*9fZ3ymtDRK4lH2mD5N>QvtV;Qxu#{;=hKG`N_P-B~!x;`ij=;E&AErbmd%& z{N&?zhZZcEjfM|QPVW=nXSkBK7@gD}TxX>L`-5}$Ep`9+Sh0DnPvl)KezWlnxo)7Zw`!s!d! zhN}gZ7QzFOj{c!yQ=-;%x8aMvE;$1DL*PgXmB{Ea-1AloH7VZ90laetgp)I#OQ8dr zv%mZ{HE=3`x6iP58!nQnb#V{;%*4(*)TXZ{L+PS9Tjgx-)!Qc}#>YEB-hZ0b)YaHr zBUrSL7Rr3+lwdEP{-LE6nWKFrnzFH_CZszn2r|bYIa!(JWBAe%|{HZCuz_gHP->tqKi_Wb1_|>qnnZBM; zUiJG6JgMHlAGwf&+ju6WozG8OaNcKmXYoG#T@9MG18}nJjXh0jSzP~=KK~9Z@je?E zxPb5g=)4me!8ql-5pA`|ts*tEe{fKuw>VYo?}K0MI<)iFQ@T1it*C59eax1KF%?C< zEyQwPX;P5=vZ~8pEMGwOxfJ}(aX<$N(G*1My;q4e;xG+59qcBtlk7M^`hM4=A3WPT zWH{>aiYk=(V6<=9y5*gfd2~vU(x;&4@wQF<2kv@_($#o3p1I}J=i3OqKL>sE7}kN< zl+&%Ux2oaalw}^fxCP>UJ%xoT??mCw<5& zb%!fhc)IbmPA$kZ=S4x9mOt#?Z9$2(1hnx<4&GfR=9ObI@-d?wGw&GQru0-urK3X_ zD>Dbpg@L6>nU-D(@5!s`z2+(Xq7pouD0~OM#+Q)Gz{$ggW%zl2XzwR+t9hgf@8uZS z)HJir<=$qScX4%%#Q8L;`EB99(`pQq!Tjm+$QV^y@gGQIFxzXMuy{5U(&WUkO z);37g`5D!#>+lCu#i4m2-nRXk$0$CTl{aDIAf=0mTiLP^ktdWWXThuTk~8^LTMPR} z%*`ir!GFbR?0VoszDEk#a1j?5Ve%#z`d|#Li4^Y$lFxaDB(5q~v1Heauzx~!|3JSK zDoENRHK{G3A~ZP)7gg`{JFg&7>%i&h4|LS8H`my1(}k zhY+y~$1Y9*)z!_t54f?m+)usw-56z5C-a<>8o}v=$80(9b1)}2RJUaXjwRJiU<+O} z;fxf356XcDpW|`1JfPrYQ^lC%1yjaF`t43ts1W0^V^QzAwMF@=UQHivtWM~mbfBdDOW91wkquVSk@)Vgt3@cKs%%lp)sgYD0}^YJfo%yNH^2FsP2kQ*hVl^U z{d^7h_Je zZz0}v^H6`kpnw~P8vS$VofG%M0m-@@FLximai;}EwA=R!O-~P1#66rgQ+K*+cHFM5 zg?l%~|3hFyBu=4M0N=_9WI$xPyLQRt7~Zj_T-tzM5!&=11C{!y@CxzQL75Q|%85gx zFOF;9x$Wg_1wAhw|DcMlQ$O;Sc`&K|-ty|9=l}BmB;155$SH;$Sn&c)gyM+h%w8?Zf;(S(1DAUy{bQ~gajcn`T%tES->0D z8^Z!PhI|=c!sI)-6x`N$IoH=Qxot3K@oBeyQB4*ubnin`J@AdZ$&Dyl-X~_bi4#?} zwZjAXrOyd-ccwK*R?m!VT<6S~;`3+gW*+Mrdu7=?zmaR4;H*f@wUpHdu|F6-;v208 zSzZCMEQ6`i`kFrbZ)sK#?k5!G>X@RpRZNkTUGe={{8uU`k;xZZ=6!t%nfB$LNPfmru_PRmiCHuDu67 zsOsrk;%;T*lfMsulZcL(y>bFX9JfU1-OGm3XEE;`szymL7ZE98^}Myw;~^At{I ziMIs|%T+Kr-~g49u=n+dJ2|e(dzyqCg+bk*pJ-=U zZ13h_xygO2PpZ|ciu2`u>AgeTz=yPeJTN)$A#j2i2cB0!eef0c3{^VdWAdB|&n!H^ zpk!+qld4;Q&(YhNqSrg%b3!*MyrUJqr^)SkLXwhzq9cH;aTk&(>Z$eR0V z=rQNj01TOusb%a^yd0l_Ih)H-4a^ISLAChEpt2ahMDLf60 zL5UC|kH#JN#80jDL&p66thJ%BZIF(GqdzQ8?z9j%0eyM6p_hj|rvY3D>Zf|VksX`B zQ8yWzhmYX(@aGJI6UPkwnq0r${k!Br-~^d={kxL5XUN#X9)|)BNG+9yoBYfOp4BoM z{ujglOxx>U7@L5uboxjD`Ho4{b-{m^bmTn-+z6Z?%gxh@!<~@8L}+C#V?*%Ay6^Eh zX0d@@{QAswZv7tI`iA$I!TDA$|L_*ate!uGEHqBqaqjB>VtB7@HbHR@J8Flnr%gUV zbkBd|`0CQW^+Sp~zuH{c&^Qoa&4oP^o-rq|s!b3KJCq>_k}<8XucIGu0Ar*ZjXuQw z)QR8G1+?^+r?@Qw!!MD2Ln?|{#=#F2OL!M~eh7CI!r#zFAaDRi6)7pD8X&fjYQX2y zG7o`SjWEF~BH|&R=zWC_;rMt%II#JXDK( zV1j2Ye76(T^~x(*u(7tWv3BEvlDuAc$y58asP!dE!Y5zi$!nq8hUgN*Y&uSt5V>N> zKsq=DdRe!V$6XB=+RvuBF`1r@uMN+S3<-b4e5g=h~%0=;oG@sUzSLxJ#k7 zPMm%IygO_E^;e}!OQvG{4F5KL>N6NZRk{L?Zfrk)zCBV)3&Wr>;Lo_znu$x1(bK1s z+E$JY!R+E`FktHucMTrEHw$Kre9ZO&oO{E1Tt-U?h=1#UxFYT@TcsUA8LSLbP9SOb z@wx>!=CtBlOJ-c$Gk(GF=2`gjBRTy78&k51V@_1edyeK^9@mhF{n@&+BZuVo-#l%Q z-}TmO?jNJ@=!Tez&vkMY@Od=kgKpCMxSmrZKD$mr1n48=jEEBU3xxvqCJsIYhbAOx zBRh6i4r^8vYiqMn%hDY>xJQ)2%OmT@1h1J^h(hybTz>3#+e3F3^cN^@$|xP~=#69x zpbo)B%Y0y>7Ae3l25Tmj$jNpH`ANBtXLQ(FDG8mz85i#FaGGpushbrf2WePGJIwkI2UB<2iBnECycQkxAUs-wXG03wZ`qC{_k zyVGH1g@Cv3T5^hx^Xs}-jzSXNT7o80(VNa+IWS`FM;kVd+P3Df`?U6BMfMFfGY5L) z+}SkMJuodaW#!fwK~U$sq!9JJ#F7LNbHYTNIuPs(Sr6yauh}_-iY!k>HPDH8nqZ(s zQ2f!~ovl?#jJWwNuxt8t=cLOrRcYXXB@f3PK+DD~i}D<^s&_?0gqLp1v>6?nRn{>d z4(KWP#;RgKSk8Gg4z059d9T6QE$jwX;$_nu&CQ(J{rUZ-0UynV{W<_Jz&;!S2_M1s zfR5a)8gMt%Z2XmtOLaLgPN=0-SdYl98S9Sjx(K5L503DPE!0h*w!r*rvmwJS>?C$X z4fMl6KQf7p`0H{AZOA}X8s^$^*%ct2N(N2}OjU*L5N*!jT+5MjaTnIj9ch_c?A|o{ zr=MpxxfkP6!8>*Zpp!Vt#4mPuW3(SN0OK9kuI)h7r6=?E?3w=r^~Reot#9b;9LC|Z z;mz;V9^g&TMSA+da5ZixWXK#WMeWI&GA66UO`WHyOUjTbGJQ0`;Umyr&VtKk+UOcg zIg#{&Q3L4m)$krjCz?<)7}5qf(Z9z9A!apRkBaeDtjoi<^shn%z}NjTixv#TH>h*^ z_gzJhih=iq!aTNHAg|D;O?+ z=SD*s}2cSs;^kd=7@&H(7&|5eZyv z3c!=M!(RjgtX+@xg*}GMsV?wv$-w(7katGom?Q+DP_~aIrAjlPCMT)bcIjpMH(gm$ z8ns3jOHcx9qybLq04LyQ5sd@aD}x2%;fEvDVM?{kj;WiK`3e5ziMhE&P*`@@jg$p< zf{iLVLO z%SNfOr8@uWT|1FlKWy_`d-lvfpiU>OX_f+3pF5W-G>1l$$IaT{E{b*oolhD-T0W+-(X3!PLK z3D;4KE|9ujex(n=1FzHDU>z$sO#v7tUOc={uhRJmhCoK9?ag;^7x}G@sZXCx?Z8(q zT&tYE3tjmhzf8b#ddibY6WS*Igk16WKN4M?j?3uX{5{e$VlU%{_&{=ld5NEtf*FMEbWD31sxc1s6{3e&bm79K zkE!c(Mn9c2zHQ>uCzIQZk(mh&CVRt=U~fPN#u(^8{4Jif4RkQjfHB4gyNR%wBLLhM z_bvf=9kX%?p3UcOEX>F{u*l_6)rhR%s^u%*@e6g%6`ne*H-}UEs?oIXxocd_-&TUwMCy zxOg$(G5YFG<6FAZ$R{Xa3-aEQ5QKcFL%MOPxD0JbrKUXi{>rfBzI1)p0^jAsu6)nG zH|xy<_7w1gj~=^3DCN9linKBbbOpg)VHz*+3b8scY7R6OdnziqC9dS~5Yr)tKN>vn zCW?7H&rj(GHw`QO=RHO-H_@uu4Xr+s_V(6M=aAK};tTk@=PqtOC<7n%b#s1>TrP

bSfupmslN-*%+92oPx9kKt z2NHMtEx@V7S>nhEVGW_Q2HcgMOSZmTuyWI!XM2};2gMc+_*{Y3;S%Z7hFq1uw_oz8 z@z4LBJS^pzw~P1TlQ+B_0h_Ql%Qugh6)>aTlk2LGlk~RxTlLSsT7MdXyO@kO@LVp0 zS+UP-#ME2(N~X}#EHErfc`8{susXm6h4|qg2TVkgeV0d-xE;d&rh9TV!6zy0!!2i# zixehTd}elS^oq(^D64AEK4f!l{!eIhQC8t(vfl(azqt+O%fdVmNO*7=7YP9g0ArPJ z!vunD(z2ppw&m=d;h8p|0Do>4-XjqIv^{wrBX`TUOC1%B0)@$$k;sOw{;X~3cHs>f z>hKIdF)I6ui3&w$u%E?!M?A()_RRp|+oS{U1_AF9--dYlA~;R+R*Lm;7#pUr_GGQe zsn;O*I34u`^4D#Lua_|HND<=-wAQ(1;@4kKtaWZ_f$#3$ zQ|rD{t0_12z1zH9$YF?Gu;;WBXBQ+eQ5sxA*f9+G<8zMxG7yMqoA0^)r0&gs*a-{# zcf<`Px{Wr!XD!HD@;46z?I1%^sAhn5CPj$n<=T5-Ig*Og_e9(7nADCP& z=cFC(3?L!_)7D_pA$Ow$?@N<(AfXlTppuq}+3#B0e_VC}zgoQd@z1CpQA^k2{R!!F z7c~tG^F|I!MplO^W<}x=k#sKB-TuBdrF|yM02%fVo;(vjT-a+sL;vNY=HmS$s#Xpk z`v$~-gY{3qmn#SBu5MW0aL<5ABlKpk0iPs>CT^#U`5m8W)a}E^p;@w)5xj;>8;=9Q zCGPhCbNXjX?s-4AX9{paa%P77kWi)t{B!@a84<6ahtoqMx-!D)ipbZ`BiOi?FLi&x z|L0!5gm)S6C2;zHz{KI3;8O@Th(JWBsDli_S%h>yz!-aul&?NwN?$|Qq@F%m94rSo zSPbv8hO7wD0so7CL!tmuMtTwe@+Ut4EbBlu(Ej& zV7}|t`u2vxCKhFRos4#aQGn4`yqEkd~4FOW(L_yuowz0 zcuMd`V*~}l{hH?=E{H9}7xHEJlBTt9Wp1unKJsg8WJ{k2@dJ`WT7oJTEJa^gJ)zX$ zii3rVOND#CS*XSff-A}?WU_9wQ zxHm+GKvLM>xILcW_V}5Rk6)s`i%P4ix7vD`G!Ow?74ygiiNcJ4mM042cvq-#;Xr#|0k--&) z8UtG~rzm&n)R~dn@S7ub%{FS3{xf1LMs312=gucuFPV{*AQRC-x0a@*dxA(tDX;gw zgq%l+AvvX%P5Apv&GM|oIgnhY-kgA3z(){=+3K^5#C4)&{D>O9rp2X{)OK&tNctl* z%txObe=)m$2)>2l{daA+ys&os{zLfl`MCo}AMql7m!Eo?TNe-A;ccNLj5_EU=k54fn!En%F z|M*75$%c$ z!?bb3kDd?&>juwXbiKCy;OcQ1@yr)bHk5^@R0K7w35)r1%!s7?O~+)P0!B)L6xS#4j~su+B@hmeaQIg@TkqTpM|cENfoVqnNbKYhSJKUBFlPrjBf8dT%I z|NOa4E8JCIUBQhyH1_zM6Km)R_Ywz(nNug43VMB$cI(SbfnxN=f>?r53C?FWL(Yjr zAwo#t{cFQopeZDvU@5K5I|(RebBHdkL^yBiw0XvUdzM_22dN5zuTI7RrbXyg)0BG8 z@>Tr?jYwwa+`xW#k&Cp#+QLGyz*&A`Kp|wJ#%BEO833h@PKUgE4KD7az-%-Z`0WAg z7tB7$C@2H245|Ny54!;25Z^zrc!s~aD;ZNhZxOz=no4DIBDV$~KRP|P7qv?j-X)+9 z_HirY(oiO*UM3_F6_)~1=M6EP8_?Fl$eoJ`gd`CKJWcQ?*BVk$P-j#?x{KByE+K?v z-2!uaY&fO6Tw5l}4J9m++rEE>0PJy;tu` z&*yJzZ@wPl+y52b9Qt}duYWc+kUdU-d=!Z*LFW;_99AZ~)W?*h#K}uCm0djbS78%! z669-(w6VgG$jP(VN3+qv75xQczTP{BZ*+Z6v_d@JzfI&xHU;0>=)~r0dTHW>!D#QhS*nZttNrusUAaURdb0##>Zt#>Je3%@ zL(4?vCRK(+iZXEm{(?H>o!@T)yLQ5+{6x178X7VwGgo<^chXeV`FpuE72v}UV$WZ} zzjO!W(1feG*ppC&({_-o0u0HBTG5J`UpG3*dJ9UXER3E!r#e-U!Q%Z2$y4OLDstGE z!j&N2;SxxsK+0;Zs%ngFNo95)L(Yn`H{i7}M*&A9w@IRH0Sg%`L&i-EnR%raGFC^K zkh2vS<6kmZS8FMor@CPmh;p0+$kdmPv9$j5@yNfZ1O7Chw#xY^Smfvn`*4MM+f{%k zs8;f_%4usT5DN`iDPp&Qz?|}endaR|U2xaq(A%CMrb^{Ly1j2gT3S^8z7YJfuDEZp z->fk{rN+Jo)?SbYh2?0j^uAKDy>VzKmDyY9vu4rhHLUDjqAI+1wx8n5^d2>N_U1I4 zgl=+?9~@jR_|CGW&^>(Zn)ZpFCe}^a&Ta<=4FKDs0X>%uF@!Z2wE$RTYCfk(xNwbA z>;NiJG|=ysZKKAAe?B~z*prN(jtp+bmzVl`^ot5vem22|Doe<^$Z$&U%;-Bji&Ddm% z!MC>bDlB&iYMMr`yo3=UE%5*QIkGp;Kxdrh_Q7in9=$|&bnk;EtunBQ(>AJAYkn9u zq#ob;9JcW@m`8kh$+bjv$+X?^)>K(y&bO1Nayc{DMPBc-og`(3q?z0vs&ELBXE1$Eo%`JV-^}FSo%O`(tCbno9eg1xYnEI+yF74mzU}SHo?N+$ zfANMiQzw#?NQvfP`G;FC5tMMMu`}<<$v?eoFR0-*&R={y0lm2C_~}NS_Sz zhrQ6Q9B3ET!6AXBo<|9%M|4i;jhi{U!bCMxE-v>vVq#%`!LNy8XN@|IRm&2oG1=us zwYsIKIa&#~tW{LP1!iC+T#PMORKg+26QIX933?2SMIatSmk67egoDl?4*&@kgk?Q* z(tmB}{x<$?*feXgSWrs5#rE8bDEY;kXVm9V737T{h1QI~O1S_!*uHbc%H_+hZ26N9 zE9P7qX5FVi2>=IKpqD#EKGHh^Kze%A2|AZq9RC0&{Fn;>`U;X>&_th_IPI1(i%yP~ z?R@mwaTB$b$n$XL$k83?t*#);reOID+{lBnr!Beb@RWU+;;aX*WJ9hDd{6n(7hG< zV${^Jt8N$QNf7jBim-l8qJ^C&=5r+dETMd8qlrjd^7Ruqq~v=hwu8u ziYqmNhwu6Jesb}rohP5t817r}m#R@y9xoaB*Ujs&9Qz^E|1jw1QiPNKte~L7t4uxo z4r|=88iI+?eZlT6mV7Ywfpt*oVc!E~2OfI+Uw$b?#HwxdsMHQ`no2!mPNP3DC+(%l z`yPMzMO47@|6C0Yv2TCCM4I0F_{ejQ+DnqCSLMO%`K$KNxe__^kDfkugs&{Fe&Wg5 zZA~o;0M_4!@n=C-hqa>OSO-Os9-^YU4%&g=9ylfdo{MHLeL17kS(`m?{Fj>Q@ss)2 zuV3*>`ch+^Z++osy7~#7C>d+(?kJcA>biecG$iMOzV0_0H?__JZQU1@6H^o4YlD6# zCDQ@UrvaQ}88EDsg-7G=KK8KFPL z)=fn-;zmu~byo&72VidmKStnRiGm(AA|8YR0bbu{5~O@s^cj?)`43=*rv7!?(upL+ zaa7K+r}$>W%mAte?sf_P(sgf?=QeM@2XnWodd%GlvyMAr5$O6#t0tktK=J$XIRfJ* zW2RX+{Z)-AfoPyqAk#f48h{=e3P(jkDlF*)TmWqte;IR*B1zj9b^VW^d@9-VAjaKl zSW6Uf*Yf7!Pisr3zk1EOOIrDzM>YhDR{)zLsLJYSg#PnWU?=RYw=q8Z`Io}@ylDO8 zM(gNBw@>z_&7SZS;$HDNoR!eWVLzKsgPtJ)B7*uGmgPhjo7jD*fD=7VYM&OI)WYn3 zXR#1Uh;mm;jTGF~^5gjg@LC(XDavateh&8c*A2W9>oXki;@HTn4;1Z*j1}}z*zX@! z%{su1)$4b~mo=hvet)Jb?1l)vO`IKXSeKqAv?RT)qc6ukTY=(7jl`B)wYtO^r3OvHhp z2!zj%J)1(i0LO*h4fvp7|8`+IKt8Z%3+$KLFk?j3^bKQ|v?XZvwa0@Q&^?#TsmiOH zR8rP7clNeBmR!+T)3tk28(R15;@RU`_Klb}y=sfSWOeCwl$38`z%LN8zEH(Y$S;{R zp=|5qi6!;>SIlV2vQL~2Gyo>QFI6Q$s`!u0uXf?eMpPQSF(PVo%ep; zOT3)etQ_q=aNq#Hm~V%ke`f)?NAK?5y5JpDMT`hN0q@@i?~nUGFY^A-;o;Y3oZ|aq zN-vy(!tfIm5(RpTJIjdkl81J0f8&}{pa2UR6h4dO)cZ`JDt~6{Ual!tS)X4x8rfHV z{5y5LaemE00yU!5)Hm#dr{x>ISi^sj-!Qrm9YR|Us^V@Z;xGvUz7u(8BdpnA%@VF( zm?wnCC9F;ZN0-8D!@1Rf9*%$Y2tVWlU;ON`m0SLB=W9m~wlBZ$%pbaDHsw{0`liD% zi~nv@S>^JM$~tt_&pvLR`Oq7iI)8ceSEDA}aCE^{=+2qzovGvMvJXxUZD=pMd(Qn` zb)$1Z67C&?1YunVdpH)FgNMBbL&PS+l9{kFA67Av53IO?|JTN`6C3jLMlZ;kxHs2Y zu<*G>b3cCt9p-<(`TEW64lQvT|L3Pa7+H5|{+Ncm<=W)O=ANFuarFzY{GG2st^5P(Tng!?t&<(7$kEU(dLyZUT)4?(Ttpzg`v0!WxD`W(a6?hP+ zgWhQ0#J|eFvZ;N}MwE+u8|RG5tGKDC@?aI5Z8&o5SPQsAzO%CU#)`cBDq=tX#NpRp zJB&u6x}$HubCf^%-R`>rv!4sCJvz^K`>rv>WvGIGG;|&R?4pJ{=08QuKQ$+K*OlM> zbJuNf?jPnrASW&XEQOUm(MC}r(n2?d=}4F~dSS~4tN~Ijflyg)`8~6j1k(1EEgZ8X z@v#d2@wB2Ux7+QamfPG3luB!>b$r)Nz3YoV+Xemc8PvZF`Xd!&w$jM{ZGc8$xyTo$ zq9Bh7RJ1?2Vl^&2a9CCXdzJt=fX^VjI6vz$3O-5)!< z0QPA(d-*%ClQ#=!QH5l*WRhfNgeGAG2typm8L*ooOp?RWJ|IH>cZ9POln4?A7Mw_d zld$lMqFmwSOAw?1s{)Y&Y|v7Bwy*!yeLL=$IdVkn^vYSA4%{-`wPaF?^|FqplIBUJ zWs@&oap%D$+xZjdvaPk1OTerK8Tv=2BTt**s3WTQk27ob+!?wx*X0SsRk(A}%2SKl zN44BKa>mRNm9110nutKWxwL7~JL9RzC8bSGr8iBisc78y-TY?sWOIH%J!aeSCGEG` zvk20iVNVb3e`sp!(Z96o?=JHA18!eBMPNQjN`4MwelPS*9PH(FMMG5&^#>6+4Qb){ zj~3odjkKf|QTGNz$AcBu@D#DyRyk*WMaBI272h%j3%6(#-;4na=_itxrPaf%%guj= zs23^u&1c_5twc-c4or^#)?iGw!E=j1&KnOlbq8`uaY({k0zh1wi-|EF9G_R%4&BKOWjNIZc9MQ= z$t^E4WPJO$yz8zlXxVZ9Q`;{8VEgKohnw>nmaqO~!q|-k^*bj_4qaAN#cf2l|7!D^ z>2vNWnlPcLD#cA)g{GsuDdyai1mc*DsHh-P6p3R>t)sR4qZ=>XL|mKT+pkGY@BVDd z>>0Ls{D*&@>u8&kGh&1%iNtXE1oXk9&<9CCk@LV}4(!?%WQB-y1uqtn3HmT3fI)%u zfK~~x4l-%jq%egPh?6*F00SoA=$U%->Kz~P@2s7+Zn5_65 z0R)-wHW})Ut@~w%8wv^<54QiAKO9m!w4-WA(|3&Bgr08&=KA`S7}xCDYII{3fBfmv z5}HumcUsM#3w>8GZd?J6^!FpJ%61zOo1x)G`A#TEqB!&>|2F?!c{u`Q8zb2T?K=bG zVg@>!CMgG+F)%x#x9&W zcFN?=Z7JU7x}4iuLT7HfJoWU*Ri4Cgt1ej{m=p|7+Bd#(ws&sXJsl5iy1RJ9nD(nK zpSN_AfS=K@nFBalB>_#Uz#XHww1A+X7{Ry~?h@EY6k(YfJZ4DrYyn^i-JuCmU?x>W zNm#9Vbjx-8XBZ^&^2b)?PT92~m{isI$8{U7-u@9vUIV7TD{m=Yc&KSC|L&f}4%OZR z{OPhX{@eRX3$;O25^)p%$1prLHs=r;|bu0j+A%7$Y^f~-cfmpHOV;|&a*KL`y@Rdi&6E9smcEaSk8|v~l zk8K-Qwd%2lkDZ=TcSm``fyFt&CEj?nYv-@iZQ~zYIeP5&D@(jPe8p?qeQ7Hn9Is1W zT|9Qtou)X>oH-xwdxbFyzTA)FU##Ce`oyvcW3S%66$t)S{B~|aM;LY}1KkXA8P+UgKgQy= z8`$m!l`||hK7o(p2~Y$F1VkXB41DO+^J@8< z*JFIfEEua%%mQHp_6jip6e!u%+n#=5)1H4Wp0jK1@q1VATD)Y_<`*W`FYc_Jc>SU! zcgAOX+BCm?;@-_$8YiLUk1d@$YvD7WEL9h7Z@+V9Q)A2FDfjv`c{dZb1w{dGe#hqe zpkpylwdQ4JvW*?5H{Dh-GCb~0=ROv2GhWnD5n*tICIo``@GGW1!fHzdPjO@M%@RbO zOCI~THFvfajau;H8GYL|la4IC36ZB>SaZvfMdMdpSzo=xi~(zy?*-9RgJf@MH#H%r`UrNf7i z!MS@>pJ6nicH0V1wO_~oansrmvhQy{RcPg(i_6)&Hz&^Gz3OUjJaOpwcK*Aj^!tyX zS!gDjoH3dIZu9ZeZ6_XXeevhB9)4sN?gxbZb5Ruo=mpRXs-pWK80`G$>X9u!I9!*vk_m&tz0pF!nckoxX-h|JI%;eNgh-fs<*PZ;=q z7#D!-M2H1U{?_chng824$w}RF_aCmQy6bS)aWi>yXy>H*&WX>~r=#cI*|2R4GImuI z&z?0el{j;TKSvw0cY&x!Nan+Ht_8Ybk4QlnlmVCpT?C+8cpJP(J;YO;qM=X>RoCvi z=JS;^UTa9b`(d=Ad`xk?X6lBAei_@kf6~qKZsDIhl$kwt1~Dl(c|x!p{rs)XI~*fF zTzd@7d*MwfOMR94@N98?V{SA1%vo8eLfBOsI~XT;p|HM$U8j^1$@S z=;}oi3LDVUmlrfIZ$CP7e`#F7q4_6fG*mP_IPL1Z`270`Vti(DVsdS<(_xo8%!Ly| zCu-|5wK{_?ePPvtl00`V9)pH+AH!HrfiZv`mk|j^WOZE!sL`!-g4K7XfUX2Ig@b z+63$9gJ~atnt*23OCE0soo;MCy?8~fS(U!0EiR?vbW=q|MHP9lt-_;{GKS~gD7iY^$ zPS4x9@vdK9aov~K@b3|FBvaJjY`jIh)Yi{D9X5P!OSJA zfAPEDU-EUp02|c-0KlgHpQ$)#Q-uiA0&@}Rq|m!z@h75j>6N@NtoKzb!*Eb>`>%NH zp&fSzGm`V;YyP&rwPRk}rrFJL>P%_Lju9Ig19mdg^7bvc`Nq{dA6-;ggEpL4 z*;&(kdqx4gOw7jGhD+8pRF6njNhw50^Xr#4c~h!ll9CIH(sx$*>YMhyywW?R4Y!@Z zyd3t*Oo82c!ij@4*s=hVccD)ULB14T1^W_$*TF_(L9yinWf7tZCm-9e+&ev~PkPv3_Fq;!vhB=Uq;%>P5`CB*a31*}OE!EHNm_2Xw*h}tSn2o0yQ(Vq*3xrAA1s1)Ffe{j zVck)b#RM&Tc)})*Q5d@L(<64?vCP1Nv55f1@c($~UzbcDKjp5~n^!eX3uL6^nNr6* zw60UX>#0Z2UO#T)hGmmyP$W_P)~5T=ktg}?j~+z2mySF-r98KIX+~jwN{Y#O=*p)y z@Mj;}IHjemW|7EHAoIsZ&@M{HGsn6O2 zOcF%u5$*^Yz%yF7!-5K)w?>3LL2!vXu=~-Idk(ZtTEDb*@^zOTK784={O9W@ww;{Q zyl`RDoHYl{e8`tnwo}7)-=}EHUjKM#w|(k%4R?jv z2yV0>pbBkf>L=c^Y~!Yh^Jk{y8G=*p>6)#Eal3T=&K=MGW98K2QoF80UASs)eu~@dy5q{nHf-JW*fX0qoO!5So-QXyo z)W8_h5--1+No5RRlfW$5D7jX07!n0E0~Hm(H3{oEu>1zP3WrxvOo6}*3M(vW3De{t z*50IHJPeA&8@u}go&zrhZ{QEVdeCq1n80@e=n~-q{ejh60I*moiF*e&WD2EoSrZ;g zU`;S`MpH20^g?#XoDFJfzmvtq;bgwhn;s^0=UL0noz#ar6X%|_%$-YpIQPh&qD*<) zUuo7=s8Eu`tXVhZ1y-)wUP@BxY`cs#viYvG0J0)u^8M=EY|7?;F}127Mztd$#ebbz zK`5vfXmvYhbJB5{iE@sLQFSo?hs-fv1;1IbP8GCi;)qhtzDVj`lf-`)|5(`)wSl06 zG6${Je7$cU)3tBkzph}qmM#0&70ZZR7w!I%Cf}f%>8g>QT+&|@`_Pz%Rb$7_oJGQu z;*>ik=Ok)SZUZa~$9o#l<=Uk63MFSHVl5t0UqX6v6iQ{LUtTfKO2dK`^GY5qB?-bM z)fY-h#;UazDC9d6MkoDDOUWjHdo_ZB?d?>b@w`U@cskT*;+b#{XnJ5g@Se?Jt_OaF zu`rogpDEu0BI00TMP zFtdQ7LdCd3{4tra`i~asEye~82N~aU5;vui#e*AUrYa{X)q>JBNI}4#BBpL+8*Ayf zMqk>XHRWbe0bs%>ciRCM#qc}Cc+nS?uC|zVG6Nl7Z z#91h?Q=godU(eDqS{sm;kVP7g7WA9)662KFhFG0i16Cg|G3Ato9+fNgF~;=R`2NFA z{*9PoB%j|ip`B>0kj7Oo?X6^TN^V?kjM8|iNv34$VS;6&V=28QgRt5>nklU$V^ONq zGE0NXz{Zn{xD1-e;ipQo)m7Bv)a6xiNtUGS=?rC;$}|b)Y^y!s&tmVV2^ptz>I@n~ zPD(0`iU^bSe!0UcPiW|e(~~7LB>RSj0y2z$;vj@&c4wmC#R!kG*%ZVwg7CoumgK~n zNW#Mfs|+r{a+jZlwRzZD2Kj(XhY>rx-wLY*h0ItNR19V{1hLMHOPMjW4Kl)i&>E;1 zqbycxmRgh4dPbRG9A)Mgka9N8CXKD$9DhKrl%bj|8@FQo2sBbL(VL|6&9x;=WEk}`Eknd*$mIZk9Yx|Y|yyii8i_Dbze5-Fq!N|~wxyj!bD)|e33M0ngO zaUWTeb%*BHX%u@+vh?^k`&f69jJw1+)v1WDpP=?xb(GVs*fJ?6R_1rET?XX0AHEi0 zZ+t`HYnZ!w@M0aDoHdzAqZ#yTfJtjfq=erK?h$l^oB zc&`Wx(i#gqSomPVB#<8{-(Q*=9JhGmy{lACA-dNpkUZ zF&a{8f`cRp$yb?JmNRoQ&Xgu6TWCKRm8Lnia7?^jtE03?W-iLR)s%fdqwuo@hxp^) zYFWB}pHcTtFqUU?TB96XiatMTZ%#(+DzM9hOgdWO!MfN+i+8q6C6|-*;(OyvvCKrO zlT1iVD9$jEYB?{B&G<5@cBBO>7@0nORt&3zS4!R+y4OfSmKA#kQ~PkgnBn~~;DmX$ z3D^Zp6)*u0W3@=i1x{{OAwX*Q=z#-x!V-Z%IfNRp$&E0>fV!~kfXO`oYq(;D#j=2y zj;n?>FDHzTU=l7YWd!_~t`sA9GHfr!nW16saHY7ca8w4)Ne&#U9Yj-+BTb!lG#D6> zu2W~k)yUMAY(}{|Da)0X$rU@yWdZ+g`K(q-o@>@|w$ZgZ7a2!W(}<{ z&)?dyDJFlu)9>*F7N~R@8$E@R8snI^brw%TvMe*Ri0^Ec#ReA0<&<7Kl29imOJ#)2 z9hc)6vsjj7)@Hg}^%lE~DYV4}7H-@B&$ObT#-!C`XEHK+45iI_jO3c0kaF~5+SVT| z$frzdh4W-_NxegnmON9Ak^JyV;#&w?A;BSvOYUS2|4!eW$U(-rDI)*QO@9 zM<=S_m;%T9P>OAFYiyOBR(mWKWh&!JRL5APa(OYMi#5=><$8z1M+7>V3`Rv5nF>y= z(^9b(Y03IRL(-g>+F+J%Bx4|b`4;u~#GII1%MGx&o7!kG8q=?*RpyFp{+CkEKw9R+ zv!|hGnP&(IbCB`tTG4G=v4VVmMdJ8w+xYS1`{Vof&sXc$(<|4n|86I}a_ZFYcEa*2 z9EIxx|5=g_$%~RdNWK`lMWWv}$`_H-fk0qBg=JoVGXP3az{TJ#0v^mke2HcTqX=+1 z4A|LtcvD^fN{`3!-N~ic$ohJ9-7Rh2ncr~ zepr}x1CR?EDZDD!FE+oyr$8;?A0M2y@J!~U9Z$kHbfmX&FYj55n%Gdw}Til^r#f=zU2 z4DmM2+VQ$Ff4t4FkJIMF>g~ylJnexr{Sj`BQc9_*Sb1z-na!ZN$E9RtL^*+EmKZgs zkIC&n`t;%$Rkg-o)RJHu)D(JA&Ki=OGVqJUTJlheJvK4cR;V`kNqtPMTCPwSq&~(N zFXd+?ZfXnI$I6-$J zsCDC}#xP1!tA_bd+GwLTowPinjLBu0IISupGpRY7B*CbzAr}O4Ms^DvqLxUwKClQz ztH2iAYmyHn|2Q8s0>I$`bOrPVuv{(1z}d(DC`^XFQID!y7sw5uF7M}N{Yy@2G$*a#hCBIVL-MV{KgultFCsk9G_;`5p%l9iHo zU{#kt50qkpBtR)hqe2*{r^^J(C|C#JOvJ?01v?)h3&j4XNT}MBq@I0AR!J(_U`TZu zRF0BowJ{)`j6j5o9ILL(e~Q0P>U9$D`)XVMJ3+TYE2p(aTLUHM{|-*8XtS+=;eTT! z)NouTy&(fEef-o2ZC^TDC|NFf3&nuzSf5Ny9lwI1daQ7d}R; ztb+;ePZ@j#l_wUW@eD95h6@NO25@Vbx}J z%SorTo;9k-SZ1GefdO_WR>JTq(h0wkE+juWeiKRj3~!Orh>vU2F$-fR}8Rd z#7Jl|=Jsd>!;{4D%n+~3V~0aVjH(zv{h-^&1@PPyD?NU?3Y&=3?O=VCN+X&RH0Q5tN2XE6itNm6fyxTsIkL7h*Osgj{Act4MpIs-}!16pD&zlrmqc zySZWSoWwX2TCIu6%E~7{*(%SKG0yJQ|9PY(*C=T0;OSodJiI zIAZ6>YT~L|iY&qMl!=FENdH?@*Y zk`E={BI)^{8UrnB1U4aV9Kq_6h%n~_6XyZEk|AhO;LsYZHT^G6OCHuYH?J7YuoC0UE2bfhp`~%5&Yu`)_no5zU}w%6&`W-ai1R>p4-|(d zCLsRg!nzNJbNs==5vJBj0NekAq?-RcJ2s=(qmIesT(PVZVitH8PT@iy zF1I^pTjCJIS@r0z|CR7et<-R!M<1ms%bePl>yG1Sj+x-~?$5u(NFb^FmQ+i_M+ZYo zeqw+;K*v5qa)YEBsgdJ6kQ^2<^nzj=Q)|ZT!~#5CpcH2Zc!mmxPw@IC+{TM?!qSic z;HVCD5%@UU}O@~q^K zlD|m41|y+zq(||vH+})?LhI00bOky{q!IyQ3^9l3B)W)8iOY#=h#QB-B)n?_{5JuL z2unvSBUt|tBp_IP#moOeH*B@Wo8<6LDsib)Oc2yt*lK?mxx!1l;i)uE6jrzJh7L36 zio!<@!JrJRF9pIV>4Q0Y5KuD^G~jfY+6K(<&~QWW)1gAFX2L6Cct4RE!CW5pcL_OI z;R+eDvDL2JfKUSwf|eRw76;96 z!B2w+(3eQ9%Nz`z{cZ)WL;e`!gyk zRc3}!dQ}BKOSoa~*s8p|v|`oLKpL0Gxvp>(?(mGhv4P4k>oOM3GNt6#jaG1+Uau{q zNTWCHNYR7U$)FH(`T%%mnz zj3K5`CuKQi9;Zpn0i^&fV<5ZE%*Dt_c?J#p7Br}ZidV2o^$JCb%Cl0ci_@!S=6Yo+ zd!YhJwS-qm>uH%rWEMhzj=F!5T2)NgUQ3gQ?8!yz^4esbsfSvAuX z)mJXmj;Q#Bnq}o0RwE^yu|}y>>ok{7A6=i(O!I$EpF*={o!&DB48@+4bi{HbqoQXb zuZ!b1#hdRQ_M^ZqsUjuSvQkSG3K;{ z&@QP{D$~dL$a7i}wny=YTr#PGl;-ED?Ic3-vOKkoRPitC^f68+qje8h!aY4QsfquL zWo0F>$1zD-k!nqrTPup<4KBM)m#9h8sP%brIBCYJI3-h<05XU6g z$jo4hIzdCI5@P3mSE_0PziynuOG*i&TxDFKR@rSDxm>FR179g7zs$rU!X%3`nXO7v zuT(K6SgU3A$>2c__PuFfT(vakR#9^}6~KrF=q13yzJlu2#l+f#9#qn6I-GbTJ&kpmL*3 zTEZoIq;6VjK=63hs8cjjYNx_X$tiFIEH|Vnvm zvz$&c%C);0g=}_!tCKN|ycTv&F?K>KlTx<0gk%kU2SMFzvl!h{k5R8P$138GFRNx= zGCf&iS0`BFR3^k}8J6@U1_I;c8ij16+v?10=F+XjIc#jF#%Q!6nZiJG3RRYhN|wr5 zQ#R{Kbm}~)O&3R~Sen+@X0g-VjGQHHt#+2bft|>ywO1$|iOzJH!Odh^^d_6!R6R-x ztM9Z-E(3db7JCdj17@jIpy#5b+9%^vbXucU%5jFY5=+pjM}m6!<)A zUp*JzR}ui_&m|}G zf7#Nx>{9X{{o;84fU1v7f#1In=8YraB=-bKv!qqh4*TJj4zC|zi*8S!&{1JDpa>0X`$*8{U)2~CN57oP3CnEq(;Tr}}BwhxT8e{}|yE>}Z$)uhE zh)N~S_V#(W|4AoK>HcFExvwkKgu$AehJS}WI?)5t2hyW&41juZWI_R9fQYTh$=#19 zCllEMN_3wTE(1r;H0aokmrRjNm&}nYg!SJwZ~}0%Ac60b+$gyXWbk`_*cc8UeEdBzI5^)Y&j3swNL?c^BSKIFbozqLFzPukjo`a_2t!mbid;mc zMg^lO2Y*j56$yujq9OxxhFRx%>3uZ3M2Cl@F438WqBOk>_j{3^fdFUg18;V)hM5H( z*Rb8k2C&gI1fQwD)NEJZO4e9?7cfM3}^rTgRlDZP0* zi;EG_)kUzvm0vE9sTadwgu!dDo1rElopcJEEbjb;1zD~?K+*(IGlWQv)fGn`t& zwMxK?RWxlZ6lvlj$qIpA_Cn{K0G;kZjWERj>3}#amvsyEvk$|pq~8SV^lhHJ%-S? za}(>zuQ0cok0?B?6(hKR=4OwmXswyvYHk(e}QUY~Q%OgqBS{;q zZ0%ss`wmxoTV=<#N=GGX5sF|*5I8(hTUq1T$8_8j76|9#aBC%@66HdeIjtj+35wY( zJ6fO;L_l>za8r=R; z!W)veM11%{@{Qy>gwBf-7`iW>ehU~BRSsZVq~`;v?r>=JkCkWO(}$+{fFT0O@1^1q z+CPxe_ppV5w|a^bp)j2nNcHz6`u#b`kIN*Y3H@*w!*KFM*V)TFejHXYkOln!1|#o- zTM^lNt>l>Gq~!VYO4r!J0eB7p^G6ak7l(}o9QO1{2UdZX5 zSZxj(ZrA`@2&6t2>!~s0fh$)3!!MhghOlxQYEdI$sly0t0xxrbcadB|Ef8(vU_%~4ITW=vaB=(P|p5p(3 zICayYW^HyQu+7iq}5dYTB$g|_vyv!{X3*l+{CzS~>emXKAIF0ZRo zq?BbQ%&PPbNXe?(Xfjz+JR3Krq}z@9jdlIw;Z}|Gh8vaTfJRBc8&)(Oj=&0@r!9cJ zrAH+1AQtwPmZQr<^m}(6sjj%`jwYFDm!YZ;N3c%*6_(48h#F@eQ@Z|2hrb*)4O+{j{e$CZrXG*`m1XyO!X%v#WM+ZF3#-?q!%^~NO9*3 zNE$4YEq`&IG|6b!<^^?@LTPYue*WU1EXkOl4d&_M3%NX;aG@Oc`du!6^w(A-{@Egb z{ZWXXC-%bGSH%GFTd^BL7BN62iT!Z)b1^`CBX&f0NDNTq_?nm`pM%Q_O6}Q+=1~Yu znowhoPVsh6x^Nz{Ew4?jHQKFhZT38srY$dkP^(rWCTLY{-49(L1Nns52i;9#fNX_c z=zbJ_$Y-G+x~Ibr)=68>i?>@qS9&ApR9=#N0Sh0cu+F_79YlAb`_M`B3_68gMZZPo zIgK2R$wP*tFc}RMj>7OCR*!(lc#Rn&2QU~B=YhKbg%KDF3M2au&m&@Wggr$_K$tuE zykX`PrU2;Ql~=@ld?pstf}U$`m{y?v*Z%p$_#m_+q`7_h^4swjr4I~+_U&J=U_bt% z^nsz!&TZ4DZ^K`dJ}?y8w`S6$HTa9t2Zlm76?iN~Hdj(Yk=0WW9Y*QVvFPy7cS8Hz zbuQLpP`F$QT{7dUbN7#<^!_RR;}^~m%Ec52rT6}Z_F-0z(tCeH`wZ}h(tCdgP^oj_ z{=Plr?;oIw!=1gK*Y^+5@!_7{7OLwXpvHx}c}Ybdr|d@ z)Dq4p_Mx^t@!T-g4cmVQYTQ45f%1b;;p-!$H*_QtBAO$isI;mG5e^-Rgox%yC@QTW zLXJa6A|awV5{gQziV)_|kw}PWj)bDp>Z8eUbU1V*Iu;!!nxkXU;q#QK>Q9vW$3sW@ zr}U2#&HYpQ$1hw5`Vf=&&=LGgG)IN2Frg0}!M{W^{uRSjnB0es;9sJ-H{74}Q)fhq zFS6X*L&|;$gi<8@BHP^``m|pH@u^7vMb^75l-MtUNEF$C$bQ#^-s+b?yg3L5=;Z~y zq0oq7W+bZ5!wmYehQ6`To!_${aVH)Z_zP8quSJ9~Iz5Ae$4D3vJTwdOpuiuj0-bMu z+n<+w02WHl!i+Z!HK64nGe3dO5PIMw3yA&1LECc68 zTpVZZGm#4O+9>|oXHsSYf`~pV!inX;u%f9WdRB-07KiMVRiu=~v`V z&or!u`wp0nMeg)W%X--GfazJ}&Y;t@UM}1l8vfL+w@h#7ywkb9Y`Jgj`%m@y*3&m8 zOalcD-ZK@%F=0B0$Gdk*h-1RE5VP>!siDBoVSbqRy?DAF=83TMfTp4i=yuS7eM+c_ zLYN!w1&;nHX(sKYhs+{_WGPuqHjqtZE7?IVCRdRg$nE4FazA;Hyz7T?`97Te$C~>M zB_Rw||HY;cRsY4N4`cp0EKdDXtLGx-uNO5Z{co%H0(0R0(!l_!qW_$_fBYirAD;9v z=$!k9%)@`k-28{k*Z+Uc;s1;0{r^_o!Ep2l!_X<5Prop<%o7oHdUVc_grQ}hh{)3; z3`G)#mVqLoPmhi|k}$L^6cK@Xbk~uDA0`v^3O&7{L4~K@+r6QGkDSz3_~{!vuYlDz zYu{L38LCH^8YoBg2vh@QsUD#!B2Sh7AbF}1bR|DS3WiJ{LW=35y^qQhy?Y^A@6soIh_?Oo+Ie9;jcXXv)^PF+M^7Ve*7(8ex5KLE z-y~iAyCl5GPLm&dP5Pqh6(ulNziULYi|kh!5br0+^cFA z$nyu0{4zF7nX&$D+eS-ytQ@`Gyk?9T`rp=sd)i)&eVS(@3pWsoF+Cq<@@G@1N2?e&HOX zq<@)EE)iNjg&$EWxHk`f%of1xAcYgQKVr5*nG^xj`mg2VVPbR>MW+lj9< z@W-e3{*n?L#($wB;j3nVyByja#*qz0{jS~H#Dvg;VgMcJpF-{qqsPim`dvdlF@bLt z14MQI6sjXmZwYOhyg<5;h?Pwb&SvEkqA z4xOhUpK_j?g!Vi)&s&nB0cJbIZ}$TjivIvV=ogU?`51uf!{WF590d3@_#yO>5XAzd zZWF)VuR$Qx4L|6^NJt{7`%&c9<)9DTC9L(mN06|0WEAWc*$eA@ACPLY5OjchL2CUp zT1KU+sRpWvYNa};#ndWl1GSynL+z&yQg>1JQ75Tqs8iId)Nh9;$qpr@MoX;23HPaI z7!qr=^g5jIP!evR=SE4s!)bGLo<8;b+uMI($#+;%{(OCN^SX7- z&FdrA(Cd*Hku|)up8N@22_oyKQOAYaiQdW-|3Yuz03pN%hJ|}}yUiwiL$Bj2k%i*}!@|7; zjase2-_Yy$N@NWl#`pTKi!%|-4E>*oo@kkftKIrY%5pK#trKsdNJ{7rVhYU(Sh;*T zze7Y%!Xl=0KP3hTt9YyX$-XI2YP*<1KPX~k=yMS*(PlBF+bIOv+tC*BR(E1=3dZC1 z_Rwcy3LPV2BfnY*OrK7GJ#hiUy6+JKgi^fKeY|hVv}yb*F@?T0HA$JClbxz?r>8*( zW&;X0&-El`^n}nYJ;C0b-6cJR#GENgcT~>a;@u_T;&8vWIJ#w!;=FW_oOG@=o0GiAYDpV(+zYJ-AZ@Ri-$ME7;4u+wDf(k;XZXn zN$W%D&4)9?7%ESnI-_P7ecBL}ezETooxe|=|Izol@Qmcg+8yzqoNfGA&l=XdU&QR< z-=(MjDa=IvU2V9iJ`-mYJ$p-sIm3v|KzhoFGn@Wv21Cto`lt7l`;po+$joPuwFUHM zWZj^kSQdw|9ktygssa(7Wb<-i)MmH%CIfX}zJr?)KI~UL9Fe=v|9IZ${F( znoqQgV4P@p%X^F@cd zo1-(<_^p9V7MFYLrzfAvlcXR)g{_zXfap4?4##1i*w&WO4 zDvN6;=uI5%ZpOdi@W7PtDhqi%Xqv^f6!azzcQ@nTaCl%!c-4ix0o2dp+6sCThr65c zZ#XyjHniy})a{})+WiKLw8R-`m#5|>oOMaq?Yd}Og@S7fmz zl5(C~kQjE?XZIs-pMQzX^~134~c|C?yosAxauEdA-(RNup>u+pJJ% z-Ac1gt5M2sMrE{9sq`SF)*oZkSk=ayG|G~wBf&#;CS~MzIY=`TN2#QQS+A$`33M!? z>n2@l(>4%Ni*GuoiDjH%vfPwN-o2&8nV7bvrDaRyvX(6qM~s-brDa(qj;AF$TegI% zH7d%Js$)6dG=lK8DfQ&IrHv&%sj6{lW8+e(#-Q&gXj9 zRondCXB(HgRN8`>xY2eC#TC}!#)F}7^|HpsC3S@yWl6yIW)^5wNlVGU={U}0(ys&C z{3h1Hc0U?^>n$zemj;vA5{b5tPGzy=4#`o;DU<^z_D7?3v>2TL4avI%ODGA$(E1Dj zIdG_efe&EYZAIWa!R-OG5}YJpTogQN0QiD88@JO7$YTOjaf43|fLZYRF1SkoyKPVa zK4BEXxJR+%TAP!F_9_0q`(zxIqfo4W+SX99&vx zi|EkdL3B({qA;3n4#m?s;f=NP9NCD)<&BiV@1qb#%ui&`@KN?qxT|bzE z0eB2NPRxb-Ao2y|&c*M`G9F{V38cYkWZe+On2+7~_`y^P+{BN^MZkC+ykEc!Gynql zB)jMs1KgJ+`VH_nOa!p!50l^E#O)8?2ZCS{+KekP<@mA%!Ua?aC(__KLwG-20KXLY zClTrsnh&?kK6n*9G+%fjOmuL217J-O8iZ|63J(MqB|y)hLimEANEkO3e3tl3zQM@I zz1+1rgUSFa@pdDjN{Pvp`Wb?zC|inEMS!nlmgW#6m)fXu4k@Laa+WzZ&0)<_n8Dh= zg<$jvWipZ=%1(Z(xgQMQW~X*^_5wwky@>F%to}zDos?`)GU=Hb%1Ar zEGm|8=G&Ax*DJvOzSb6RU`SoOn&7}wGXl4}3>BzpTvp{sNXSlhB0`zUxQ(D|w3iti z4sc`;mr$Uup{N>tK|&nO#W@^?GCL^kjc&%6NFZl&c0z)qYFT5=q?R2mrT$s7{G||> z)cvYcVd11QCXG}w$$CA*#Ke=y`hye|M<+2H<>X?>)C3OY(~8mYsU(@GQj#A`XkJ~P z6PJgEX*b?v3eHk&J$qB40+s+6G1W=k$@udCoQlBG!` z8E4V5+3II3aU_`}O;%^KAI8R|RutJ(EF)K{a#cz>IDN4dRiwtn!uaRqd2;y-g_)63 zwHol!A*Tiqyr(G67Aw`7NzJoYI`iUu1Z^y}Di%t0(j<$;#l%`jaA#maq}f2}$ascQ z>s_=?XQyQfo5>ufOyXE6|LIJXR5`_K)|kNEg`N$nP1S_F8L2rnqtr@O7LKJ-5f!UY zJ;!As2TG0eI1)%Dv20YH+Cg}=&6%y)q^jGzYW_-ZRn_clTBnp#)`=!1_%~s^8ubE7 zQ=6YPBzudff zF-e!35kZh#rd+QwOi>UdYl%VV0Oep97T}KpAJ+;UWl?e@x3!eya!4|yS=-)OkkHzc zh@|NG1m|j(Yqc}sd59!7wI&pFwy#~-zO1%tM6Gwi1TVfWYwzM_>ZIxbCu4lFxCE_K zSuOK1GA^K&>SjXgq}l}jg9IzHim~~TE6HfGBa6plL3Wcd$%XtjxM58IQ*^W!IIAVs zppr?HQM6env4hRzO37I8UV0X-Mw`$b=rnq>FHNRNCkvzi;ni+%T>+8{MBHh}3`7Me zkw7m5sv*!Ed^h}Iff|EXA0Q?q&Z&hMxV-@~fJ=mFhagg65+=%4AgKfcIf*QZWhPRf zJ7!D{!J~G#a!m9ciAF8H1t}~z5P~2OkAN=`yB`ul*!ZB=2Q(CafY@OP43n@vA1`hh z{uGDlAy6zESRgbT1FSy_1TgqGvB-r#K;DD|NCcuR5LI{<&^E{j?alQ7wP)RaXbb+p zqd5Y=;FAd6SZE&ZRA7Rle2ST!*cAx(J$xWzu$QKSiTCmHtXO25do@9lQft$E zeq<%HwML$kg#J~-xT@UcmRMJLtR4K07`FLUmLz{*3qukpeiEf%jVTG>yc+@GG{$HO zva(bf%1R~Yv?6nYB8zlcxis*#rBbjAVrB39>f@CN2F$iJG5r*(FGjx zPOKlb=Gr76wIuhLL!RY!q^hVKDi)+Vg=tH{#2MU-v50co(~CG6K@c26g3lhn74zI3 ztdxMT)IkNS)mpinrkfXOfiBvzH&)&3E3&6rtv-}lTUKUv&`QU+*D14>MoBdID|C{o z44VH|eb+Ij=CQcc>NT6|D~pqhWE82RSe2HZc&*8O!?+?eAz2gqe`fy;hU|*Qn~T}R zpeDA<>W=~Zrdb7Bq$J+#O3WjamWMRnx#~n{oismHX>_=p=Dg*EN$zT)*_#afHyT$i z_!Xq3QiXvu(r%8-^VQpONs}sOJ}|EJlm=-|Dr8h#QUxhj+C=jCI;y-)H!_K@BIYjR zLoqQKhVrF5iJ4=rvltZJi$5Z~(vd3yGqc>@7GyBTIn?&}Mip=H|B6kzZ zwN$;#<@90-0NEJF8JTpFRO!GY&%RWtRD;r%Dr3yanHk9m zd0Jg;2FsE+1(tQ+Fc!IuI$is`N)215bQ|UItU@lIZ)%uQM%zuaR_(RL+mcGXIrH1x zWx;uxT^bdqFlJ9m8dZ(18TqNTl5C#U{E4sdI)+(z^$VkSOEu}VK_~TlJS8z|qBPT$ zB#kkqb&QN9_l~>X%zT?*DB}?S_a*msGE7c~CMLmVm(Grp$z%$`;^mb2fh||rR%)Gh zrv*|ctT9lCQ`$|eY$jn;s9mH?KU00RI*D1@B+VkYI9;`xVs%pEIf+W8R%olq%Inbh`>i$fPMZ=A#Dn{JiNksmBOscMgBaq-QI0tHFCy95{4N zjiQ%kuq;1T(gHpVc7y+d+rYN!?<8lyDmM>cX+Rd3LwZp$ss*c=ZD4(GCG0WWfv!e3 zqC3&OV1w^jpslZ?chLvvGdM9LA*6(^FQp}6vkslimSz3Ul1{n#Kngg zlaF8T@Ad`Ze+uVg;D%!nO3vXY0PwgC!8MqLFz^Mpcf+CZLc%BJ z$T*$cF@ra4-iaetnnCQsyO1DJL8(MhBj^ z$Lr7?&es^*T1RiPXS|;~hoaDEFpy}Tc-?FYjMkZZOphTeQx%T6g0I+*_WRrv$*^l$ zTeJ0TE@yqK$)DJCn8kz4j5}x_rlROHa@1@dCD*J$uP!#(xU&F^&a{~p7oM{*uQ_{? zy$*6`b0QGr9)=g4-e34B%WzMo@`+R!t(p)2&{mv&8yYyA;$jrVozstRC$GSduEk|= zcXMY!flxRMwXd&PBfRe_?qOW(esnrDhi?ls%EeP4g@zgQbW=3seFQn9*R)0&EDP_m zjVB^-NcV?mUNg69V1VrFBhjl}q>XzVEwGVYg+~@z>LcxT^5@OmQwU^JI9a&&5jfhb zIf`xslY~~ZHOl>!&nWzj`w(AmCLgrl$3MmG;~s}Hpfu8s3mzDFl6$H-8Mgb-A@|wa zBXF)L_t$81B;?iT&OfwTYf{c;3UtX(JP>Bw{fPEEJ**wkRed3rZG=(usypVYK|V|2 zN|8=^@@Npo6V7aN)*moEuqfC{M{HgBxwOscBIBgPS$IVvcr*7#k&ZneURNgAW9eR0 zo3hxf*Reh@#12g%0IDm&oHT0Cq%6i+tuRtQES7f?h+{U~Yk48rzo|605_D!nD0gyTU&flhuk0fbcs3ne^>fY<0P78FkF z>1|fdtD1blAmh6<(!tPVjlK^XrVhn^+l`9HT89*Z7z-0t#Nq$ zi1N0Evw^DCt>_yLTkV4_=eAbWB)O*nXJRN4h%Bo1nQ0ed>^n@RQfy)ReY6Rp@C?K= z8Na#ORUJvV2et;9YcmdH^`|U>pZn{UkQW~giyUOYR2wy!DUZ2@rOhU{(`&7bI;+t< zOEpYC<79$$nkc8u=c3(qcLbqUnl=Zk@AT3fmrOL*?mFhe)7E_R<*i3~JkivW=5%H# zUcIHIrMj;zkYTPHs3wmu>PJskwF*g-GY2eJT5=Agfy9)o{_>Y=KMHS+Y)WD z_~QAIdT`6=gsBN*ANkK{u6Fq*AANMgNnfz$miv@;S~}`UVaulO?AIx}ia9MxX04}eLYrK4U4tWfAnW>GzX?@)={Oy7+H5e* z`W$WchbZ*JUOV>(lf?@vNO0a3WSl3K99ELw=Djp4cV5N{h;YN zE&-=@GQt%y8K&xN(8_#%Gq)K&mcb8n)>&J&@PAxahT%XtLvT1xef^8baW;ND6tI1Z zF&$JBu$Wd4?=!pNUFmd$Ze=$+y(xMq4I zmgo|8Fja5ywW7WIEGFtJ_8bK;WF@^eyFH((rPxrKA}O0SR=0jxFaT%DGJ!f&TeD|r zisXKGmQeF1Xa!ez530!BQfwbO5IN3T3YC3KXvtYy@YTn0V=`Nc?WFgdz((SZh}#sP zx~gGxyJ1$`Vn}zb)pfqa0K5!mK;d|3;!&4@;RWsJ&fwP<6TH|2xd&Nrlr`)C2;(%LgVB)f znB&jF(hQ!_gkS|f1&MZ8S1PVM;al+)6K*Pu77&r$@QvqXc;3LT>_dsg|B9>Oc)bSy z2i3^}eLItQcGLw_l`EeC9N}dr#sgTh1{T9hZ^9p@5GH~^8hCxN62%l$KuAF|`TD@N z2JD1DaUhOyli}QL;fnABZie4o-C3+BfQEr{gL>nxgXj5emCQ3S$ecN?1Tm4T80dpBQ+K~9OpGB?MNpq(JF__ zWUF;__t|{k3Lppg)dgZt!UE6Q#-?^h74?ITMLR6PP|WP{xfl-#lO~3CGZY=pktyU| zgqRS9NLR#q8Gwex=46o5>Gd^`WYkQXX}X$*6MgN6I34~F9iVMJh@o3;aHc)&pvk4_ zK6f>p@>%K~Zqi3(DcX~8R>$VUreO~~-0qxDvc2vE>xfb80-LoFo?%Q?j0M)IElh%K zqMK=&q^T-~27SVZLRpd_-7K7@>k7N$CfG@~TwWbuefAv`+jobLZKs-Gd9;7c5)?=iYlV`^FCo zlW@c`_pia_YyAvzqXZp~T4@HwU+*=$4)B>xUH~MM)d4CroH|_Put%!B(QAAwZEfa} zHMz!cWR9z?^PI!U+E`)-8Lp|RtFuj9;BT4FSglT9{Zd3%r<**!m?iA<`C{IYfaf5W z)r)9X%(i_~grovK1Zr8FMh-+edz^8P*~NO;Kr`(1SXpPlj4X5@wZv8BnQwR01Syxx zZ-Q-~l+~Xcq-<;&(FqUfM#yS~$ui5#L2&dn>2p%Hz`Ot*qyuEs6KCwmmo|Gm$(opZ zo9RYwK^47-w%bFEfhv=QqU;_}2Q6)sg9$d!4x7uCBt4XeZjU(wu-r+Kc9S(|fy{2k=IN1E^l9azOWVXcPnYEy<5UdK9DTnDilmlpB zg#?2ikGKF^{K7c^1YYI`3@WN7o%vvZ*V6f|Pf$Rzp*AuQg0ECJo9)iINc@%U#;3RO z-`QF+2S2l&Y*I{?b~+r#4qw3&^ug3 zuIlU@Xo|K6N$Z*6>Mu~sj@a}bvN6HtnwkOcpx5e+3}w>8wS!gUOPQ-pZLXi+?Eezg zPhA?g`E^&D>6*IhzZ$#yx4*qR_SNg_u7S(1-yFCUE`P~?^UvY()tT$Birw?>yZ6Md zDm;^SRRyDwc(PVpfc@kW(}{ccesalP=A5crbIY909yDZW8(h>fFt9rB^aNTU*gWdE zz(jT@!iUnCXcfxY@3Dht0@>)BxVLBXZSIHnP3&sj`rw0GTX#+Dd)R&3=AHu=H*MH= z`nsl(E!~@McRjYRu)A&R0}pI%+g;fAnCte<-CIVQ)}6j@L(^jV8IvuN1XG9<^s)L3 z?v!&`~cQbLMU0Tr&&-c`Ncgfhj>8&pCEAfZDW{X@tYokF-oq>#cy|{JNVsg zn6d$9;K?Vxoo59s4nS6ckl=+{5`JNM2U{1sKE{Ifk}xZatEL`z@nfe<0+nCH3QFp$w?>xH^Qld{L5jxJ2Z&+ zy&D!Qu!1}c;48XL8#USalbyHL*ctx$V z*_?1jKq2d(<5y&c7cCqbYHuH2=m?|lwEC)BfqLI1hc1NPE=FdmcTjwM+@g7VkI80V&^~L5mYIQ;j=sEND zc}IKN+v2Wl($x|Pl@%1e&ZSCwEq8bYyhlqV=@^nDkjsuwIk>xt;r`Wjz|HqiAzivv(bdP9$^j19zFsj!>*-eO1m0lXjoomIy3e z1@&<`?8zZV6*)1-T3xfd8df0PRWwDPSZ%M`FmbHY?K%!6Juq|#y8<6QM1Y9E={X4^ zO*9ZK#2g|Ar@5C#@6LMitS2?;e_0PU(^8<=$jBE*7HR%dh}CV5f8Xl~u$%sU`(%F< zyT-HilS{DPPQ#3}p8c3Ug0Ml#M}!ChqTwWxIZqdC4+JPr!jn#T5(xg-k30T-c1H($ zMhASe%O@^@!^Ah^&&?ej)SDe06ZO=a6ZIXC3wf9}R7u&Il2cH+qST4a9TS^Xh2a9V zb*$Ca5tpR06_e}Amuj;2*4OvqKTY}Q&%%XXf+?wQEzvajo65bF{*Cxna+8?Syq}s= ze1Bo3SP`I|NvAH|Q>#s7HABr}&E%AE9l0+T>nJ6luB>id7ffDT)@;z0Rnu?HOj;)QiJY2B8>McN5{kxJ4BNV8^46-N zYWP8f;t4W{TV-pNY32RKeJb{-+(x~=74I_cW2w2QrgU^kInq72-%D|D8W=-%8P;ot z7*lRM$jCNPKl%Hm-v89_Mee_`3B&qnF;MCy=$mQdi<1A0(xtp8W41ivpaL@I}cT%2t-PtWxAGte?D}L_X4BsG_N`CaBgeusrPsJFrzm1^8mrDrF0e?y02Z za-Yg68Fi*Y1F4&(gh(9)F|1{1v3>udt&(EKlo9(}rhz_R6@v_hTQkY<4HtAiB-i69a6wr zl(EdH04FPHbtU&yLK#_Z$SD~qr$-}+O{7E_V&NIPa_+8_uiJ?eK0T>Y8BdAWAk#?Z z9yw3EYijh9$fX5FDMz|TkMH&~&dU-=<`p?*Ja(iyONmcgAJ&sla?RzGrVUzICAC3H z{FmUo%!e|%%Po^rnl@_ZEfQ}@ZIlu-(}$H~Y^v!}G^*e5ZY&Qa0!j&fb#_KrUkOzzxo4`BlPMynWVDx2UcM@) zCa0l9ASoeIcM{&SPa-?d{A{FWWz-dAq)bN{!Q?#guIbWPBB>-nC61MHqId4g=6*r;#+irGzxljfpkm zd5IAvj3{T6uPmo@G?ka~GUd=d5l`einG0p!n*yFlB$Ni7HbKOc9-nzHNJN)( z1c}R~94R4PD%&43khw}8HKMTco>D&6($#OC%ae35i%UmbpeeqRgK?%E=Uw zQ?e|OsU%;OQ}R{gu_h5nN=OJJl1#cHCB!TLKa#mJ+RN0{!+4pxa;g$KizF)p(IU}Vs{lzkQetZTH6y)2X`7{_s8L#Zf9W`oHKxiaE#6fD zmTO5P7i8K-)NjcIz zK&$xcsd4DP8%4=LAb!2)?iH2qLE{RYQ>BJ3urX`!Uz zZ1qef)ZxhGONAlxQl}%_$hGNyFg5Qo<-o$3=Ti_>D zk3Y5b1Uq}Z(v%#aDVba$cB|ey(5s>w4cL*Y>dpJ}O!l_2Z>Fvk-(2{dn9{2Q`5)1u zai3Tjz(}w$($oihdZtpN3TwwbD%DO-75i7&A5uNJyNdOc5>Q{*x7DdH`1MRyW98UX z)>xUZ=~bDwV%=pLi#e6inrzonAJ&j{+X8+)({0TRTBg@OQ)?rli*1w=1&P&QE@;qJ zu)Cj1YnATD@TN&pLEzn&6WOiBSwE6U>ybEi1O zr-e6V=_kLr9Cf4`Ob}vK_B+zM zR#Ie2E!XScY0^N#Tqz+F126~HpA6{%Htdrjuu*H3EwALBDN#qHggl1D9Pzs{K9Poi zl#m!k%8?R4t7&1Tvh|u)%6f#{7QMQg-q3-e{f?V@wNqe_j*h0Srv#utzyBLLn$!kK zLZMAX>PtB@!c3#Fq2v^0x(wHd{4R5kqJPS2(`8yIb(xa)XM~$mZL#wHDYc%wSW6Kx zr|h_rdRE)l5+=+hZYo=-?CVO>%4erZovF%~GTb6lu8fw?uiclCGvNO-nWRy++K5U< z_bBs~>1k3=Z%CeJLUJ(TuQPS#zUwg&ZokPHvNyBg=B4wsBhcgZ`Tl_8YablKhJLRgWp@j0DS>caqOG=3f5?!=BBcYcpGGXs_X85n9z)aG!Og#mEN%~er zQlJt#N>er|ArlmM5cY7((iHrHCX=dDrKFO2%4e1N%Jj5Hu*{z#HMQ6#UYWg-Eitat zJ5mDZ{eNu!BJqmUDk*11GECXOMm(U*FT(?34{G~Xf#BujwA3PP8zp?2nfx+pt+Iv6 zwDSHbwOr;L>QOQe6%FHCKEOQnq{3-LSg#FU^|Lo;&CB3rWsb3Cl zE0e(zqe}@b$ICfowUb?Sdsye@T_ti(Zo><67eNj)Wh8|5qSsU)o| zXFvANv~@d)-KB&?dMQU58(K_~6hSGW>@e^fszApBzoDsUc}j{Zd%!4Pd56-?Q;2mW9h!oRTCSWq;}TQS`Op@vqWH?ApD1H~gVR@WI`SQ>(?F zh3BQ8Qr^USyLatEYbv`?cuI9McdPjG6i6tJX5!CzyTe3}`I*hv7G_< z?uNfWD%8o3yKKtMgc99#o|JF^3>?db4`ze^kRLh*j)Z|z)ZidEIF1<3@$T#ZP)KIs z#8v)mRCpxUH3X*#qhit7V$t{&aGWuV;59m3JKno0>|W{)uZrZuM~Cwf>hhyjUcQ7x zeN15!gZil@m#;kP;H?MmsjfN}z7XS|+vl%?L&lsIkJ|$0B_>kiE7ZU79rVk^;);cj z6V-6M=STh3bZI}DmPT4zBa!Puq3a4GE04W}yTOu3SkU3O9J}(c?FVf=<%}~QTXE>DVgRkjnBnJL~voubsIK}nKnTGm{nu44MyK#FxI|I+*zh~ z@aa2Bssh3^pa=0eyzpO& zO?9V>-HcDmQ}na$sjj!B!kuPofhb9U~p|j2Q4zDATrK$$z*-gzU zYB{3cs<6{;(>@zU+;&{D{I-A-zpbNjq|#&SQ%YzdlPz)KEqs)O!@Ik$5BwGk@-Q%@tVAnqle zn??`gp3il{@PhMy*&KYrz)Im`nD7ybMt!W$Ek;8#lS&5s!R`Qj!YJuF~@06@}kSlOxWE#TU1y zT|pG7P1Gl2`GmtZj!O6ey&tY?6d0+oF6_(f*^@!PFCFWyl2X#K_y#=&QJyCl0!cgy z=dJD{&IS(oHk=Lr>~y$<_o>&zhg5(^^js?2-5CHtp8{gDsT_bb{tG}USpyVc4DwM9 zusxsy?cA7dH*eO<<(^3R76cYLHiQy-9HWczcfrm4Q%~vfLt(RCE_Zg0vF0j355ERa zPK|}bvCx@kjC)I1Mk@UWR*s)YM0 z0xX}RgoO*WSfyo4n9G;);~~WH#07AgFqUrb5dR|ngV?EaB|l@+!7o7rRcMo<-UHk! zXr3t$Ugfw{tu_^vQIXe0CWI4)1s*Teag5&YF}fd1XOPv17pa{c6?3Z|`W5ss@!^4Z zX0(@#GO-2}sOq7g*7B|{Fy5wk2#WZzK7;C2MDI@Src^M%Ce!qN@R15uz{7>_YGf!` zuffyvN4mO>9?C8cjlEOC(i%V=`wM^L&`8%s8bl>~G%qXMpt*~&W}`i0NAxshvEJs; z;q8-&^NH(;`#>(gMSP4bv&Y$K1C8E@nu4dXs!e`RYRLJbNo+&=_Lp|=*A6j~MPLHwwq~UASpvn4V z!RByy!-A^(*jFZH^$UZ=n?KSpab>Iy{O#4{Z;ajd6F(q+N&F4jPzp7nPSl4W0tlmu zEz>2f`WSJj5r$8h(*d1f`pLt4xjBwLva@hbz5KkW@M>{=_V6B0nnHm4_!||!+2Z%7 zH%6XVxTLOTaDGjyaz$CVf8i4SnG;&4HykP-INS}HbS6zVHZ(TS5AdJ(_kJ8sr}g!v zot{`O7xOsB>B&aac(rtMx)0r_8CBdDHCdGnH0IDmqIRIJE3FjK+ztC@a)UKSt#mtS=bI z6@0f^hclK;`lHoIGKtz39*tNVo6#uL=Xmbn(H=6w)YhXwv=_7~>O;NJ@|sp!RldrB zdi6vkwFj$z^1BVxIKA5F<#9KdlIdiSejynQK&pb_$sHF?H@4w5wZj^VYiekRMz-C- zt7h{SbxjcbYKbqLY82MU8dKaoC4;k)$qM(V=C$MFi;BA9&6=@_j?}*P7|mVG5>Wj< zc^#BMJVyOGWAtR$0lAv^20u#id|Mo+8_^*M;(W~3NHvm?#`(hR*=XG2)qGy%o2sH% zT#D1Js+f>=RO?Q- zUhJuY2PSsu4&&j$fq}v6bcf{KmFMc-`E)#yh|`BB;_<}v#`7K8;jGE|_RgI<$6wG4 zGHPY`+Q|Lmi%UkhcJ6lJ{o(MnbW}5_Cu*T!?NY>#G-LMy&AU0B0p7l5&6=@g@B!mH zrW)T_Vt^QiJx{#b`8n7byPx_qf60M=n?b`dI`Obeu>^K zGv-rR^UQXGz!|{fPaK+FD=;6Gk+W2L$~#0C`~!4Rwkz*8wj6?5I4 zp#Wb^#3r&s2crEJ6;-Ya$c~NJkx^R>6YibeRXN1ZqUxD8UCFFfM+~hzy zmkPk+s0~4#f%vdRr6vO|3wAf)kwGNFNeEsG5A&}^e3C^Oyo%(**?K!$QxS?p$>Ow`^Xg&E%>bsdbrbo%6cqS*`QB zQDNQr^cicot!J!pt~;O12)U{ox%b2pPS7i#%NE}+)d#(5<P9|7jUn&TGzS*K9~Q{^#B@c)*Sw;O~VW62DTot zd3wNPUP*3iUqHK@(QZf8meWt~?Xm@;@zC&aC>{;ix_aw|mqw#YhYOdk3;Ba9-w&>I zt_u}Li@9|rcV8zIvTDHo;DNni4o!;SPedj*ate(gT&ua2U>%6pcBw( z=xlT`x&mE;ZbG-Ad(r*qA@nGE68!)@hn`12MX#ba%HS%78w@?60AB1B_9&+et{8HQ z+o*sDsT_ty9$_gAyKI)i2+PA1EU#ho!s?T!JLCZzFN>W%43-!!!TbRdfL9p0f*}mO zA)J8gCV+9c0cY_T#b0U1HWUm-Tk$Ro!tJ;)jAQU004dywA+7i*z7_5f$^azwmB(t7 z@~~MCv_oi6r_j7k48uMwrn*DOlVv?X2`b@(Pk>{AzN`vcrNs>jqoWOZ@RuiqEqq)k z)eRD<6Xs{#V1Cd^!CwgSaUQlE!1+45+qlnNRddu)skA9xw_ss9W}+XR3Z%ZEcoG-% zr-}7c&jQD)!NFCI1y=N}-7%MIrOOqIWwWuuc`7Ir(D7q?ZKBCmL%AF-N63W8VOzvv z510>V@c2EoW{=NpuAOJ@G1;mtb19p%!RyGlSaZbIm_SaQ%<76t`=Smo7aX{X#oD4T zTe;2FVl&VgKA+8O?&tOnEuJ^DSx%|q86z;U!(T#i?*C20Q9rqDU4sxgXe1C>sSSCU$hReb|=t7^5I|a2PFHLhF z)lt8Gg?t6Q0{>nnUm+*_g*yKjBz^`N2(A#VDhzE01jW``pC`^D&Lb{`)uHbZufnRV z2Zhiov@zwd5vp8@Y?z zOMae&cqYd4R9=|^SV{6I2-w0~eHa*)lu=&sA`iwmTnwO92M;d*Y$Bu}&}Nw;yvSN@ z2y{dIKVD}_0kR2&02E>Pn@nlNkPdGU*L$%Z$BPNR5j=iFg?Kv|Y{7uh6i^v9Yc*l2k+!B1w%j}e#+Bbl%u#IyebXN#FG@3|Dh)Xy4HF@ z(RENJXS>60wOOt6=eD-?(brBz61;>T(UddZxOjAQG4;oZ_4FyDix-b_S47?YOP2Jz zqu#C-cXPA5rRyM%^{W=f+T6VH^wT%4Ts|7K7hcp66l5muvXYcN9=B7Z)fE?h1^W`- zeBPVr3ktaxEL}#Aj&eU69knf8c8dNz>T<|)b)*4zbFnIN-P)uIdy7p#mJDtI{Gajl zkB;_lv&VP0*6nkh*&VA|b^P(GS~@%jVBrw7!@mxlkHWJ$nf#4G{2ZFkm%*3DeSk~0 z$I&YORX*{}@9=tfQ?u3Wcg8#TA4j|JbqJ$sjVaG<|` zV32bRt}r_s3IFLEH=e#^!RjW?KqeJps-7_ZP^+9+ODD$GKpR}}9}WqE$f#sk2eFt~PHZDi2O0KN;%?#v z;!niKux=VeIkX%d#?JSCmJ* zR1!o`aXyg65&CfywK`M zWNl=Acy(}aUXZ?hD&prU>A7M#@4!r?U0mYv&S`Wv&T;dfrz@r;Us&EB_4+I(hucpv zHjCeCas_>{BTwD1;ZzRk2q9G1{5ATr1G!T!JJ7ZHYouLIbliZS)-RVkPC3c=hO$=P zVpad0ayK-%J38=ZDu5Szw)4}Eb$eE<*t5Xq3%VS3KP(t9eukp#0iV}yj(LMSc4L9T z&r1GiBmYiX{)pFkgsI7m#!ulgxwZV91-;0>ETDM(+L3j@|J9av6=|Pz2gQq-E_l{&9hj#tbCyQdtcgUfiAG09;cw0OXe9#Y!s6W# z;o)QXiOCdm{A06yBH!LrWoA7(6&*wvXzbux9SR9)eh{1*cmw}61j4l^t5 zf}|<6t;gprEFm@!JBi(}?qod6!62gXZ2`?5w13cbVY0)TSYBHPNC{xuddLyx4lsY1 zq3a5LZGBTy!}@iFKg?~0e{)BpbLK=x3p>`Y!};{{({M={XB*P#hS0?qkvFw$8(Fky zWLwMPY$TFJ=R#f>u8qB|<91TwchW#CBGwRFVXg^Ltjf#}ODMyX^*B+{RHh)NuYq?7 zycy<=Sf=p{WH9a1nJW~&ucF-sU4N3d1v-zfC{p%jUB8i21o{i*Y4p+6Dtemqd_~6I zEE1pIB~tredcGkhzDpJt3&i`&YQK;Mu=`&}90`1T8SF1lr3ZLo8GD4N`kB)x2{aQ~AtGc_?J{k?+DY+E9G`2x+ zokM(uxQ4iHYCTqpFHEUlhN{!#fm7;(Q94$%y=3fn!SOubI~r}r_;aFiL~%FCeip_4 zl7`W3qCdrB&@1iH(Ow?K3MVT2h&w{hf5N05P2x}xu!{GD0KbW`pJ|5E9YsHhc2$=M zkBNmahwJ%A;C|Ww9ug;j)yCJrpYHJ)_7YwlGVqB|b=c&i3>4K;&j(h6eA?dB!9uQF zKi;V8-SAA=A^1%l?}Z;2_w^*0DRz+1T~4)^!u694%!gDS3FfMedQT?C@%%TGnYb50Cbq zE|}TCOh>e8o0KQYjPvVCdu+PJG^loF3hcuLK0H%T_^8YM)s zRafbTXrwZB(RB7NtUOSTHo0h+PYF;gorK;J81~-M$l#*6YewJdQ z4*&Ag92gH>f*hR^B9`dM*C{NovDG)`MoA}ry_}kb)+(WuTCKL?E)ld!;i^n?XO^|r zE@5D>k4Q%DYr7NqvpCRW@tz zx|z34K3P@T_@z*QdO~uesJ$WX#K9R&Reez?_-C zEM_?%h^^n=C}%&6h~@(hOePOJpgCN>Vnux+s4yFzc$Uu#H{Y8~-iw;b*b286UshtZ z=EoJ`b}21}$FGfcwf?{2E)U+d**`|Z+}p+Np261GwNdVa62swAyWt+9A8ZD;!n)lq zkoaFEUPE5+L!OHkp%rL7ItU$(jz)XY=h0c{JaiHGV_X4Na9=|=01|!^eY*?>VhF)P zTx~a81_(g}PuoUVoJUCr_u1M7mm;c>Rlt9VC2%q$Spq+$2YAmNCEqc*#cv6qeJ0kv zD%AWhv-2JMsHpNN!R^W^n)Q+yHFjNBq3P}H8}k+}R3hb=-oE$#GvI}F=u#WreqtV2 zKpn~NN#otso4~hBuz_kr^Uwyg9eob4>@svUx{>#WcnCZpo&zt4H_$uiJ@gl_g));N zu;r~I8_6zmkX#7%yx_ma7{+5TwBap>b%K61oA$c8Y92r;Z==g=jJ!Q9Hqr@A#YPun znNWtIjjp0h$<9~sVO6S?cr6U9vOukzU8`K|NCs`n2y-#f$`*g)o)MJIP+stLoBTde zIsNpka{u>?q!?3m+`uaLMm<#i$!uERmVh?dS>slk-nwgwze|j7-6t!JZ;vs!Nqo3y zj_D?^QsMLLTi*6K7`vTm!j_mFcE$m}coSQ}_}1X!e~10;r8=_VikX_*qO(-OV&XQz zU{>nXV!yZo4$;om5pWsW+3MUTcC6UZ6E`YlLULBjYx!<0v89DP^q#?m9iU*(qM5D6 z&UO$y?pE@)PiI4P-zQ*&>s0biCCB@9Ru$;?>azSd`8SF7^j zpepm%(Avu0ttS*7)w79RsAm%!&%?i3U8B{df#3VB*f%;KaNGUAv7NYb!>NT2OGHGe zU91YyV~QuszoKvet_RwtXBdm(3e!}3J>7!*#{qm@8aLiF#31}MXli8 zOC%13T<&jWO z#qWs^h`$p5COFvd2%svIKpE5w5HSL%z7f_#cB12925~;R1YHR})n7+;)XYBJ$^C)zl(PigHMDYf`o9hbcvq4_kjR}dpx*0@DQ7W51?_bOZg0+&cix6JPMK(m#M8tu{uIqvV7xU)`BUF=Q2Jo zBY2ME_l5$vmK6U+;l1!F5(6j(#Y08#Jv;&73B`5(^+BO}!Y5)wS++ad2|noXx*UEe z1s)>Z*-$rIj6MXdgiF|u2Yf?WaOLO@Wx>UU1yKhcB05`L<7W>vH4WfD+SQdz&B@Z? z>iW42acjdNYmPsD%^?kqM=T9=<`c=zV1{Na%_n^BNOa;HSD-aYcR^-Xs>Zc)(F1Fo z7Q4e5PIY%B<9Yi=YSq2loe)nX!lLW=oCd78X$y6u8mmvvG5CnM^*P$>hjm z{Z{WL+T^Akw^=MMS0v(TvD>+r)9s$;a=8z{)pK~Pzk*sgN!JjB>EQmy9Q34P40WH| z>8^vnTTNl-_f2*?<=klXd+1?YEH0iq!0z=HR(l+dlUy$6`3z+rjc$%aHb+NadyU)Z z^EurXhPK+@_c)-=@GkBQ6FLIa_rga^#Fr(lUaOr%M|d1o?%WW0tkv(jz~wS8w)&m( zt$r(aL}#F@%ilTA=Ocfd?VDc{>qgJOk0Cz0aBp3#FWb=_dnUDcb1JiOW8u*#xZ?ZG z0l%4U;lBcqp|K~rq-mfJ_@Hm%<77uis--$!RXg0ZpmF)xw_dz^_rp1fu0Pdgb~&#P*MSRv z5{=i_6}|%vOy}|$_$&CX53;9_mcLOo-2a$9Ldb2h)n4rMJQW`38`+Y2Di*tT4tiyi z#WdnR_%yfu$k35}6xqr;>**x72Q`O6m!%_7a!>HN>Q3%oG`hZqv;--$&#}sGqusRU z-&^hGMc#BDOLnj?pJuAQ&HPR)*)V?x&FrHldWv;GyVg|27uS$i?W3$m+IljKEonKd z9j43Nssoyu4)``Vf#~dE{hhhUPhGCls-hl~^TQ;1E#VC(BZaFLhC@RE)Venmt>yL& z1pGaAGTz6APO`XeW1`NJY3{-$wYBSgXy-xhs_MccIY*?;y=PuHJYqk%*HJy-Sw6=e z$=R6gnf?s?-`6*B%Jwx(;qJaZK7;J2?bu#*<9X+G(MJV?u8`9i8tdi1T)|+e9lv;% zj&O#K@hTmjO_lnffO8s5DTKe`wW1p$e+J7G4oIP|Sh{Q(m)W;(U*Y3rOP4aW({U@A zf5Z_-pzqvu*PUn;q;#D~)MuAe70(dD=LQ+K99me`Yeb{~)*}qOMDR&KI)GpJ7H;r+ zy6zya13|{G23pYn)O7?o3LY(m4d%l;@4Qpj>toyp6rt|GWcin#x5rj^Q0wDSMfCDf z#uo9XDwU@Y)@zK<`4DM@zlA6`M(1^uqtu`E95lYK;v9Nh&m-diLTF5$v(>Ua@4=FH%mVtz_khsfAG+ zKTCmbFqv&WrXc>u^Vh2-2KbLlO!iN;>HW{eC-9?xE^A-Uvt1#9ar+{mjBG*w3yJ$A z%lS*;26PMDT3{hXpI~eoFP;^bC*~4^Fdo-{XU&0=Qxj8%|0}U^FA@#>xmB^~i`kf# zM%;%9@T212YqAac6B6bACRv}q3b*lO#?R=o8&9USciwr|7oqvG?fB&qr6im2zp5yO zv0WWMU8Ik2ik`@Ehd?~ZW5ENZT+AJ4D{ikyDa?B+`|cu5U^@*ah4M8?Qz$-8&fRcGVmw$z}FO}qePu* z?NB_)6QAL^7IuR0KG5Z0LG^X8n0^UPEcp%bK0c2JfmRJsZM#rET7Z_I)#w1U86Av{ zK*yl6Uh^1z6!C0<&U`2pzE^=WENtfR!BJY_+`>HG!@&!Pc`(~l zhCwOj@gcDB;v>IJ(+zyV2Rex%!$>D3L1sg~qSdE5s0kD#6e;ev3u|&>Kv^+Yj9~&* z76QBo%XlS$ON8jL#b_l$$SWxvBEN>k$47xkB>WE@d{D)geE@jy6yD&|h39f6rM0IV zUIZe@o+R2?f}Q6V*3Gl~ZC)GyXP>uD2q&_lt7`@PkxSJfM2gwm2l%d%2TS6GD6BWf zi;-Xz!9h+l!>W_h?}VUF=F{YOAVSF3Vki*RJ<8}GFAFA_WIMlGv6PSb5$DqzHgEp> z=FOx0zD81r=CO$XQ7Y6G!C$cq=N@9-`~!TCRc5Lw1StIVqTT*sx`#rr3qO3pQ_F0Dpx|itUO*RWbM5IP`|*xoZq;kK~xG>KGg6v^3IPH0tg~@YUFYqdcm@ z3I4O>hI5pmH2%(;RsIXM7LLI&G;EM~$j^27FM}P2AsjOUZ#`hWrPSWCo#-NZc#ZBL z9;F}VPwfiAE<*#vE$o54;}NtH?3A`bw5B6ruVFXrHk<_Zm#1S3%yO6x%+1S4Wt>(e zXka**W(-ylAOI)$1@~@13fMXLRD-RGb@gDVBv@+k<%P}4*hMo8ka}84fYb|)JC6JLamO`HB|>V05@e=oGKqd7V#Alf)?053@>a`Mndg#mgbC#!tXw|8-;njU@%~;ub>G)2)C( zy8(Yr2kY-k!SWl&j=LNDUml0Z(Laayr+>mbog_)xNiP{8Ys=sh%%@=SgVn}5Rbdo> z7~Yf1fGR&raZEw05wsgVQhmS=JCZn(XetTE1PBwnJ_OrzJal5km!D|hFrZLX(24}5 zh{eVs{A3WT$2`(XPk|zaA6AqMc01x*g(F0G(40-HM^Qf#ZBfME;<_CaRh&)q!0clXT`tuuJnQm^V!D`{jn0IXJ)*(a8(nk6Jfi*86v@o zy@V6?=Aymg9A!ArJ;hj|+Pe#97K^$EEE1vUnFajZjC%q8g^GVTjb6r|@K2d}95!E> zwSb>$|3$oFk5>o}1RUQ>Ttz$pQFng8Te5tNe5fA$c=%Jz&=(+j^~GSN@&s6^JP(np ze~1292CD(&jBF2;XpOOOsNCFiKwL2dEUYUnqZOijJeBZfMObH3ozWjeH;3nxL)P;;-wf#*%Q5pH~l8W-y3%h^0ApWtM{Kn3z*=j=V)g-Ng#8$U>r+`_Ob9 zBG;BP8Z74^$yg|tJVypLg)OyPd_MSi|NUygkm;Ec<0Z}NRjHZM=KXG@ z#N1Ofav5tEjbF&4j&5o?`a$jk6np~AU>MQ(1+N{cV^%i7s?iA$C+pk5h2Nb-dY9U| z;Kd(t3WNI?Z>E6NB$iO78UzwYu=)eVA2@-{4`8!EekK&ctHgMAV`BNcpd8grd`aS* z3Ewe8OPXsMD1RW6@%yRz`Wn_}cDv0!wz{G4yO!u2N750C!N;6v%P0hW56_<;w#O}_ zg`LVf<>%>_relV)ENhK3*(@8gW-~S3`WQvU>b*7Sjc7wx?V>!xoi+ZE z5r2)-jUH9pmywRom|jfYx>zod5hV#Iq`oBx;iD^hM5 zRtyRAWBw2kA#j9>y>#Qsey^lY*`&~?Np`ewpsrcbujJlU_WAg7~+4bS9 zaN?obD7@p0E+0-E#>PI;M(f>PjzQISWdmS)hv%ga0*C$yPEzuhj~@k6XHu+Vc-=%L zg!B-x#5S!0<}H1^_bm5l(M2?jS^-oHiH zSn{b^1oPWH@c%`8sJ}0MTFMizN(h`!>J@r zG#*DdKJ??D^L`8w)&{_z?ih5!Oh=QaBAHOx90%(cf1|G?>C2K{a zr?NWZ*o2eIBGE#wTrBG{W3EIJ2{W*eJ#H>9iEb=0x_wrE92$zFZ>mjme_U>usRhxf zIW7o9m?V}FSLc_v?=_ZNg$uBDE)N3br0{=Lio0^G?ilIn;-i0#{Z4n78VR+x#Q59S z8A>%WtbVJaLWPSxLcSb3UEXDr}ujs^?WS^3x^u z(6ce1)wa}pV1r3#!LvDpN>pd_f|Eqe8DfHN1O3~22Hl>lhSB#X7h|)nSfy?xUHY^yZ z?dHYt{3P)%qF{%x7aanY9e2W+;E%$2;ANxlSE5Z;CWmKrWW!Ka+3(NB&@Qq4=dIK$ z7~7S|;L6%wxjdh$55lzMy9Na+MTlD^4~HpFLPbA_7me`&Vj3$dq6RTdl`GQ)&Z)@7 zVp=M}bP#2$BDDRuc`BeXZc>E3H&)zH6OT9ovf+8SjCrrBajr65f?2L{8UYMa$H^Dx z08isJOVk8WH4cZ!qW20XYJWPqMP+iBUujh7?EGwbQY64}_a|F%uLMmin44Fm{or!c zGn&~%vLtlfL&RQ>8qsAiTOR4p0r=qgc znc^-NKgTL5(s=dlobsMY#@NLTMH{q4ZoLo@6lLQ9#5(RZ-lH zy3jTC1qtp-T&}2=sj4{sws;c4_Y9RNw5_y?Qc>K|rB6xoBPJ(%VG)G-yaZ97dI(~_ zy~m?j4sDU}Y#bs0**+aat4yz`^e$nCxH7cE_VGoJu?lbxkWn?I)2=r1Wx?uwWf+a? zh|8!9(Rf6k6u&FGt3urCl5r2~YO{uW8U;t83Tdt>XKl~&UUxrMf|42u#~&A*@uK>O zXt+@Gyx_8TehE@36fY`^J^8Miu0}U4IJ~WlpWw8xaGy#`!Ye!C%I67&Ao)dn{>86L z!AF8xs*m?dT&|0fM(aU)`ExQ@LqMD$;ibl!-(8A|s};ZNOY2z?NLDKxB}@GzaYTt@ z!7KY5;!AMC#uLPE!87tBh%?`W<`<*PV-JIK(HGH|;bi*n;nOwHkI_pIP3`CCSCiSQ zV#5Q4pX8(%Bppa!9*3rSE{Eu2$%3yC#Nom|mS8I@`B)k$YP?XK?Bv5&Hcsa2slU3#{h4|5BYiWMXhlbN$o`-Mbid#a+D{J% z{-BqJ>so_D?KIs!6l|>v54zjzgM;=qcVWBIKQt}n5326}e?@;$b-7dZ7aiQ@ZKvl@ z*kP2KL$`ak{X*k0s<~xQ-)Hn>9GtRG=`%VC8Gg0TsL$jF3)B$N3~`3n5+}mG*`?s4 zbuaNMti!K@_`(I{pjTiH{T5jFzYCsOe}qWGAESSuPs-?@c);-r zn9^rdgFL0cQz3xja;E8TS^-#owg-Ha&hNG0jQ%_PRDBnZcV2uk{o=(CW4?384*JC% zI_>a%l^{fhyJquV}hmsvpG z4(=3FV-bhj0fi4BP9d&<)6H)HJ@z5u1>%3f$LdhfT)zf;D372YqE{ip`@8%(BL6_+ zBqCYTMFz+!GDXfI`|(L485P04Xw+XDwd5>DKJO>XbP-C&w0i96Pk2}Hb3zS4yJ?IRmopBY9c6RX2xQgPz zfmcH>Em#Z7BD3$M%SVU;A6uCBi<-3X&HLSUph>Qa&-_<;<=&t#Ey}CkFU+Rzt{Syv zG$$i{ws0sxQ3-#Gsl|^I^B2;iqc+MMwHJMQxfSZ)I!};xxk&Y^X7!*FXT4yWE%rYeixnDMD4Q6u5Btl1&;aH!GL;;6U#?X4ctA^HPD#z=ud||g5EC8Id)ckf-@>P)j_N$HW8(DK*zVZ|FGRzi!0n+M^yp&3iS%^~)v5Lq;$)m{KWI3BWz-1%< zU=7+%bM}B2m1pc*TwIe8mSpg{OcMejqVTOP2EeLBY)x}mV;fw>NLdJQW7SIm#{FsbeD4!KE^)K zA+kYnWrzQP9iB71Pa(f32QLYN(IbVI(}XJ^-uXQIdVVbkzZ$Rp@IQ3c$H%pv%6Cpj z2tA?W&nyS@QXW8Zx?=M3g)_q5h{bC6IV?_w@>8_i;bYRf~$ zZz)+RQr6R3bjJR-#?4s~By5Y{7hr96zr$o_{BFO6t@2jym6wp-_0W|06UuD${54~? z*@{uabRSZ#D7~n0WqzDrHc}mma=)X=*GN-Mz9xsyQtik(;QwmNyNa|=x&z{)LjhAd zKt(KS3XZQpRFyH0QpU%hwl z>f%u#xn#04P)Ay)(=$9F{d+-~bbq$gF`iQ;JP9Bszam4Jg*aGVqdqX5zzdCKV zB;n8@?}|$j$C_)+RrT3uq@LOmb@t2~a8X}bvNdN*R6$;2C#pW+$TkyOf8dg1j#+YG zgSBl({qk%k8m;$;$90UqEuE-AZ<0>Z;GTT{{VlOAen0-;&+ph0f%7}e*}hmEoVhV& zSM|C)@2h^!Ef?+CbI~p52nTAwAu7q3ua%u#c=Asd~4+{U*1J>j+o zT5Rd6XnkV@&Z0 zenHmO7>;JMg`wh0ng56m@?%!hy!h=DKp@lpN4^z~aMBKpx+XueUlF9>X2w4*;{v1HQ zc42_yAuWt_3MHu>tCD-i+xPCJU*0=zuYrtVOZ>hG|duf_=l8gztT#i(e znRd}_p0LSoig@PK*7!VqgZYFn8Y{KoHr)$**`M6bygBB91akx4Yu>{=H8w8=DP~i) zBUhKs=f*FCDlp7}{r$aPIEnj!VS+3T}{bImF==~F4#-GobX2?$yk{Cz!q+Hrc9A&%GAc#JbrU^?_66CE}u_Rm)P_$P=ofnzie!HLAiT!$w+@CP<8nD3-`%UR$! zHK&2LO{K8mNzNmFQNVmTf46TC=64;zkPkfVH61?oH{POyw%{KB4sWLM*u*Zfskgqq zr>DNY_lxN`)8K4vt8Q;`HZbut*+O^3Uy66oEu^L=mSR(dv4fd6Ke-bdARLE#fqtug zaG;@KV6bpyJcHIxJd$ljZ*$4!EH%R2m5DQMbX>fpCC**$E{$n{N9H9P*JAa-Guk8$X#9A~RaHU?{fw5K?8=upQCNLj&5EXD)cC|DP4mP&zvbfUzEw0Ew zy0xk;rhDtKMX5D~UgXPj}b|@dma-oa@WV^c7D; z!D%(a<~nkKnb3VeUZ69?xy2mL>l6lOs0jUqAyw!dywk@9J$@H*XYnMQSB3EGR=AGA z6Wn|JA-&G=>Ui~2AK<=uUdJ8(4d|LJ;+VM9er#9f7;@8w?3Jr7jG)UhbL`hQZp>Cy zXSlZp>omP`uGR;CEChYhp>>}h;fKuci$jL%Z?_G6={fGLnv@0AuD$u!^}jkIaIBAI z8qRShQ!W2*`RM41<7($NQ~|bFRkAHZG(wNy^UfDQ^!H=S^hk*>JnjOuFFW=>$Kov& zP~iT~$- z=IZ6k)>bXLWYy7&kA8afcY?!*R4+vCrV%(t+7WKl(0E_b8+@!D2-{Hf@n)U^f9)sh^Di@kd7W&TX(yZz7oX8UFV_5JE)FvBeOo_o%@=brth5?O7J&lH}X z?V{hrI|Me#)cY*t&aur>`lK?Ln((#^ujkOpm2h$u6k;xG}U z5c!d#-K;_ol*ij^u0IGq%E)^mq@Y~fkkh&^}roSQk;B^<3%e;Hd71=I@7hp#<`|UYAryEg#_|Jwyy*l@w1-d~_F9BG$j>7_CMI4%MFa-AEAad2 z?r!2hC-QBuD^mXLXCPv_U45}>W4x~n2~SaJ(o?VR;#0GfLVRiK0TdLR=@TC2b8@UK zrzko*OtgE&BdyMKBz5aChEg=_$>dv>*X`W{A%;OEC|)Nqj%P<5&Z(whlb)BNVG)PFqLlX+>Qu(mutTcd|GexX}7A`O0QWnId0^F-M!UFvWQ4JiE zTSFwMNC4#2Du`fpMNhG{rjq`V(DG$#q2#;9_SH-3(Zu@7%8Cio@kyWo-Fs$S;PXJp z=L3O|Hkuv=O5bTCDc%j#L#NWiQz{8T$qz0EVxpr!^w7)|DdFi()coC2%lO+vMAfra zC@v&a?6~b3O9}e%>Su$-J@d@Cpl7*M{RPO~X{9Ri00QEQwW;BMW#?YHG>E0NkmCGsa61)v1SJ&fMx{O_Trl~=j zHnU;&rf$T4R;|_;=Qd3VkACqEU-veAw??DR2oF~-Hg6+`{)REU1h7*|;jXD^(50al zvUNw^JC1_Sq}Rc#EFo<7c!97a7$nMtX(w4Eqz$L6#$k#TnCT*7DFIeA=}+goJKv`^uW@Nv1*=KkL3h{78Q}y!ey_(e#+>552KMJ7e0;i!6DvlLh$Uu%HRGJ3ert z!3j&9%WogShWO4>Y$BvVW?j!Q?F#%XNIMgD`PzrB9*$4@WS5y9gbK&;@BG*c!0$4< z^C+B0Fi$)brQoBO%xeTG*3RpOjK4mRVkdd8j!p-{`Jm0YwjhBbu5Nf5UrvGN|_EW{gwG?iL?Tuvik;1A{wGXdOw9om1IiPV8ddd zl^fvD5&^-&kq?T3hPVE#&jPNA03RYK=Y){1b(2)$ix@E3r^Q6#eaqUXlUcvSO5&HG zFM`?_Li`d8Q~Ox^s!bbLw?AfiM2|H#qRxF^?V}=?|JnDI|1*tu6(uJtlMRytVnThq zeJji8BIHR2(3C8h3e)(j=}=WF9T_4N=qL}hTRfupJ`r@VIxSD+5yX!O_9;$@_Y2PV z&^j>yaY4LeZ~TsTc1F;B$PoR@FVT24ew{o*$Aky&zaPJjeDF`Z@lVnBQ=iB10~Em_ ziku`-0*)30hw;Pw`E-@oTOdmk$prpMAp%VjrPd0hK_PH^y~xvB9)iyDBfU^svX?~e z8^Ck$p({aNCV?eD?jfpxQ;^) zy8+VmKvfY$7=^G?Nqc=E^ebk6Oo}PXGQa~w&YFIM%msmK{sAFNx+Q?rPB-X)Q(zGI zx*o)YEAg7dvc^&;23g9o$x3589nRFkeJNA$L--+TF8&e!NLT?$S|s7AYD5X$`0kXO zh;ru(1fI0OollEADM7TzEllp^?V&($Su=9?@TYyejrEe_1bv07kClG{u@BAy$v$d9_F3ly#n28e;S1oh-pqtbcG7!1dv83(!o_H zBZ(8(%Wxj*Sn{PCR3eqZ(Oef1^PlW`GlgN>`y&-C6v>nz5x7E%-2)IH}~MPN!MM191WpjZT*nzG3~I1~wLAb)v!={1vn- zX39jJlN6zJunv5i{0ubTiK|-7Z&$**0Z0voPB)H54=ioy`BFjS^d zr=WjteNilXn3;7gD?se!^Ot9Wg{9JP_tdD+SYK!o)-YySpr>c3?{p7YLvpY<6!EV} z1hw9wa%F^v4?l$OFGiI=%Dlzm#Pz}6A=HY4GemBlZb~;>fvM~+W7*|&DZgcK`+4P zp-25W-kZGh&`0@W-lx1T!6*Mc?`OCP={nq)M#G(Hp0F2Wkh2nu!r?9wEmR66Asxul zG0@Mx5S5}zxJPZuC|pgLaK!t3M`Z6C`=xBW4K_J(8N#s_1)Qsj(yB}xFJsS3@GY88 zO`=j7*nK4U$IicueW=wEAt`Q2Bq=pJYoOYWFf8I>{E!R1cXYcGJFOiyxkBN@*@)6Sp z-|LUetbIaE3D8r5MHNM2xF;_7g|*e)5=tDQ&k3M5y9qUa_ejrWRgtX0tOnW)&N0_5x18~r?BW1u6>RI zastuB=ScPl@jAi-F)EZYP!-5aDvwY zf<1@Kb>*Uzn*F{%Mxrn7Mk#0B$7^EuR}2;6N&~uDxx>G_$U6!(AHRUm^E>etX;KM( z6wF^ooi7C}LV3;4i926QHK+Tl;#CyBTe1lLD-;2-J`viLhMT){iVG5bA zG)%1X5=4o{CYIsnv?_0nf6!EkLZZNz{5(YNf_Pt1pj3%ERp}CCa#WPqTcwB%O7wPD zc*oOX0YBc~+no;bcMA^^dPoHoW1N`J-mQ9vJqs>$;b46$B2^y|Jh|v%OlC@W63tYL zBktNA>P2l6hsXw(E4||QG@Z;Bi23Pm{(f44CM+zdfc8Vmu~D&+w0{)-LLMUjADNfX zM^x-37DT%RGTYG{Ul0FSb*fq|pmce`rE*~+4FeNGiDuHHtWipzl3aepWL`l&+wznW#e_-Op%TRRQ0_J?m%8ghL;Sp> z9*qo$^wL&n)iJ&i<;8j7xUSqYG$zPfDvr^l3B43m_VoFwdq^BXE(urX$j^aUkR-M3g8JnW}9^hM{ALfe{$QuGrzEW?u zIFElsR=M#flx$E-QBXk0`~zr)K2TN}E%)aWbZtBpTH&C@Gy!ewa~8;p0@%m{_DwX?6sB5;~5QVr9TS~nG8PzFcMgCZ$jcYf3MKF`KZhU+?vI(4%6%( znHPhfu)>%s@iGJcK*<6YG6(;RmPaCsxe!~N%9{x%Hu$uW1Z_k2j>0V_Is+L^UhR?C z1&GHUg1{5(XDxm{OI|ne_i55hvd!Yn2Gt*2bwoCR&qf5-D#O|91EC6F4-iRO@Z}M~ z1%@@e4w>2Hbz;m%fep^S#l8SQt}YGQ8exD?k0(Fm$-|f-90?~ z)gr+hw*UbWxFc^ruOK(t3xchDA0h2V3-g5Tki{qzQxPKMuJNEfXt7$LQt3tRegcUf zElZL3#UeNFV6Pl%0|KQ2Wr&3Fe9D~?`_OJ;8io*gfmto^^T~39at{G5a?9j<2;5_( zZ;QI+-t-EEkGluoTPYMF$~Q(Fz?X>v1foC@U&=@R{D>%lhXB&Re7rJf-f4FK`DRpU~Y$C<=8Gi9Eao9(2%HH$OM`6n`WT zi6dzb!QrGyrDc3K3Jq1o@g+_>nH%zGu;0uBj=_%{h;x_@40m&cgP+N-lXeP{Vg!_r zM92q4%0D2La?5p-s0F3M3>iQr_oPz*d2S-mQ+z~nN+1xqc?mtdD6xBxp$af4@{8fS z=eR54+=T8j&p;1W-25Q_Ma=H|&4P_&0iBnU?o%@@Xt70}2|EzfM{<5$J*(H@?n z_{1O|y^q-61JQv=aHFc67Rtn-;A^3SDJ1d|fQ`fVR0!N7v?AZx0EIkWC=y7ckeKq| zyU9?npC{tG`vTfMgrSt59K1)_`arF_H*zaapn$&<_!|siK|z!+KQ%N}4EBMion95g z<~-(uCwMx@oOy6(&@IGrMwT}0$pRaN7zS(*93F|@WQi*f_Xb1=6tIKj5GMtr5CnxD zq>BL_wFZSjYkJhe*3`q_;9-WaxSU)rPr~COtq69e%eZK+eZ3dAcslC)j`xU%^R!?A zwm_BFDzMGB!_5Sbfluu`?{nTa;6V#QQQ$4hMdQ$H)CD&`-U+w%o`Cw~H_$uKQRg4% zi&3~irB}*DdL>aE$ms)mmz{r@xQ9V~poJimHBn&KX-PVr!6ZJ3{y_vS{Dz-UNNtso zbXG@?v3Y2bQmT+D^$N?O1tq{LWu#mxBO^dXl7=uDP1I=tu$4iU4pt(0NkCqbNz-)f z2iU*BJ_I1xzghj;-2{~R((Rc7=cgAdbeQ>=I=t=9{4=rZ4(@1{%{0vu%*dxN1Jkvdd%$_JOeuzJw)SPbxAOVThtufY!>78O@f+>|ali8EG(Niza! zqs36E=;^g7#xue*+RH0OtQ1FkhDUg=$_Vxg;?urY%Jte%c&mI zTN%L&FG9o@327lM@DsQTAYmvrT_+6A@bjhNV+=)x*HdCIv1LlixHJOl1w`%=TIR^x{jR3krxO?oCUnF}e6l0)udgP-=XCEb0&iQv4|DtpHi19A$b{tCeng zsoEAnEzhNnYTP8bbJTIz|oWBx_eTSdr; zF7- z5)<@E5SdDnE#^WN+J{+5*a9{+$Qpl{N~?nNlZ4oybTn0AimRF4<0fgsrH*!=(>VNX z_gT*Pf7bW7a5}ERg*>{R$y$=F_JKKmA;|>z-YyvD&jx&#fFtf{O>nS={FEoVyKi=P zPZkSx>vh5$%ggwncgu<6$4`7RYi2$2#RjNI zKa0np3HStt%mp&$@9zr5Fs2aV6aG9N0_zlPGN&QMnn^R`0*5Z!4T?f{J$>{E6y!84 zkD~Vd{;ps-jUl@o$`POnJIw%QrbcHTpRe2E7WF_e;_pBen(9Uvc{`=}~>Q^8#OVXiAMR|M#MJTeKWUV2t* zfYv8Od9Y4IVvP`^C1?`x+Us}k>D;*d^^X=Ve0g~8KjHdO(ojcb;syEaIpYI4a1n{_z0vg!I?y9Sp@-K252KH7HEtn z`1$AY$-~uMYtFu2(2x_3zQ!AUE8^DH&b-XdID{U?7j#2qM-K%=qlbGw6&IG{?@h#^ zsRo$mEbxt-7s87s7$XRa(o2-73VD<&g4VI()ie!pj*!#?5;Wkyd*9~!YsaCJMS9%? z{G;40Z{Ka3P3RiJ8xEBi#wO_|A4QLCKHS%K6w-#4`r>mfyYP2p-oXddv4vB{1c^1bP$r)sPux zqIrbL$3xt7B=8~fhoUAzXp{D=fEqD25(3NkaC-Ia_`SU=ri@?MQ!#nVF~lQN1rFin zp`qb5fro?F96W>umKEn**;!q)tTQ(=J-cH?)r2c#9SAR6IBkp$ADx%uk>3FsfUplY z0z9vq@kuz)Ot}b|%6eK^$wr`IPdP(6ALE(|eL_9*mU)zHT(#ry(EU>?-!!cnpL}}a z)PuztdDMF5e|-kzD0}XXRqG#E+{%2*LUGUAv#XA(V+jBA$yqIW$J~R7_|gCZo-%?b zWq;G0=jOcu2dD{4w4R6^ImjK+JIrf%KAz9KMrEMgXg8J7j48Ym{!s{{cKC;x>zOrw z|NG>uteOu#sLA@_b9)tq)0X)~5OR@zzaf&SK`rBvF`wze32qRO!svv{z z`ea*@-uS9LnAC~o7+>3h|4!&MiE{Z^Jy#L#^f7%0QPfI^un2D<_6SJHT zm;=#Zc?rlVQL3c62rfvtV#Tu0@KqFXp|{_-+yV=I6+gFnKAP?b6ITAuqHeltLD%)S z?V*9@l10n{dpyZaQr$8=QF!I-KZtEwIgASnbDX(Kx#2aiYwkh=OrQlCM<|SqbXSkD z1AoN)WDkY?{4!oBmzM^ANAu6)~?_wxqJ!gfQZFCbf(jRa$u6h zQi&b*QXTo)UZXuQQ$<1)d{EFpus?y$>hcM+uy`gL@_iLU#h49fnNWy;Xy;!Ga*!)uyUK@jv&F zE@|t2`@PP2tsUpz>S{9%T41Ap8dI`mYe_cz-cp+FC|7a7djqQn`!D>zr7KnqT>ra0 z9nqyd)7#sp@42&~qhq?A9^ngGDXY;~U}KLNa?n^_fRo2`R69V)$J?uie?@i1m#qLE zf4i}`Q&;Q++DrH={J68+r8e%z&xAzT!9#c~-42HmkpjY)Le`UFQUtk>jfTc6Cyp#B zkV=nyG$JNTH@n0nJ~{jNP67J$;;6{nJ%b<<{^Rlh;l)@x_*GEi4-(p>=G%kLDnfRo zPr3j6o?#?BFmdiFX4s0?yR#E!_VmBth*!|iTJT=FD=B-&!6M@a_9UnFOjQPAQl7%& z?qO0{;HaZnEH?{F0jm-ZFR#tde^OaqBMB!LS6C9N&V{wW9D}6 z9}_UEPhVv;THtqto0+htFe7Df>|kD!G&WgR+_q?Jy1pZ6adE6PIyJtS@v>iu9sES^ z<-iYm0pNC|lbE@Nzu$_#rye)HJrXQO84v18pVPLso6}LgfCnTHjAlPD)<={tJbVD} zAHHyYloOZPhR>jKDua3Dz4xeWXAtaQAUYy<-5_^$kV2Vmkhvxf*5DU6;OF<9)Cs9E zN13rBtzT!{0aEsdI}^N~q@*{1f%LxM!T^OuB&h%lSK0&%*sm;1a2UEi2_OG>@eywy z$ymL<_tKg*9^M}LX=#i1D}_F~*f`_vQDCGp6We!w_}F6r>o?lvga17CF!Mua-q44~ zAGra{j=F-%6G36VE_meAI&j~`k9Q(1{`Rid-`s(}XD*Bcmaz#n;RDbm_y~Rh<>7kc zU8C?Vk+WRfA*o76z!(8h9{7{Z6#mDK4=*wmBh9a4zQIROH5H5-z$SCB(j51_qdv_# zwumdkH2}<;xD1_Q4xp#-1gc@=t-OY*@2#N@^*T*YWX@KwRsRh>#01Ef;Rzt^A1<7A zxAS<7EODTL0n`gfLEdO;(Q#Z|i!QSAX7@snH|;U0J!!?K(sS-uL*z}gs%?F00du$( zYtY47TpfW=w4elj97=BiGxle*uo;fW z2^J*r_Y?Uks{9-;{q!@u?2FIQ`cFSYYrp7u5kGwHEPmwdi)iw>vuM&;+!j+i{qDN5 zmmB)$Ex+ej&&rScsS?{a)_qP!ARi=Od<7pr`w|elqd(^09e+8W-mgD)&%Yjg4$dAf zym63!3I3%UK{>opvGMeWC~$ahO<}`@8$yfrznhEK zq1kvp-SO=Td>)umU z;`4%k-zvJqH$pWiu^)@csz5Xfl@S`XRH9KUBNTi{P?Bh(ln}0zN(BDO2!mP#?pN4^ za-<|>novXzzb!J9eUynVZCw7*7x;6$4F7~rpem@OS&R4=5VdhdJFa^jU&Rl8hu=eg zc>^wVp8g$5`570X82mLlgg-hQQW^5pTomDN|x@8EJ4fWO~4ze1||=^Tb$O9Q>Yj40?#Gw z2k*E8cjZ)OqEFd%U-~^>6fBqpJBLIIz`IOrb(&w>O08J=c!$%dAeQ z0@m~NH=+L87(vaoV^>WcC+uPJFbR0vvHeUQFU#l_9|`MS(wa0>i%-cqQ=HYIbnoe7 zZ?4&WI{5AVhtFE)Lzk`Yqpz*rA|eC0^Mc&A&S~E3cHSb9Wj6YAtAl9zG;k1o_5M!l zO#C9QL+Jcf;1}*3zQmHV&SLhP0l$mPJ|D{z{CbnaNBOtj{%zppS%B)TQ&4Bj?wt=z z-WiIM!jWn%y-(YkRy%ZR44|Lqrp^jrLF6gIe*PVJgHr6n(|) zfN>fNY-;Q3Z8B6r&~5X!SjXnO-2)DmH7h^a2M(4laIlm#7rc&Yt@9u`_){+S_uBj^ zj<9oa0Z?7=+IVbM2^$~c zz(y1#!Ob>`kx^#_w=&AlQa=g4%lt1RaHUv1WV11!!S z28o^QAOeF}@3hrsx6bNqHrRK8mENT*vQ9-en9Oth6EVlZ8DKwt5V2>iYjn28M_DEq z;C=Zv1KhIG(#`fOwKuoTizU`IEY=%3bI<-U z{>@8uRaPL-S7y~TKT#T+lxDMoVlFdS z@N|@?5w>x+n#+G9rB9bPAB-I6qgO+bl+o#8lcFiPnj(*_(up<3fgl4OeCh(1s~r z*690i=Z6=q-#M#D_n~gTIZu|Y^%iUiD^JZK_n>gn~ zQV{-q{|~G074hll0p^z__^(TrpyVaCX-pLEi;4<4O8FRfpnbR*T-$e{d9LOKv17rE z{k&-g0E6RVwysW~eX;xH<-I~aKd=#(4Y(bveq7Rfc)M7<`;a3H8IYCCF&;sVDtM#cBfZ)^-JtL;@QN}8ke2%n!*^`#YP>I}}MJMQSjJxkZ8 z4CD>v#s$Rc)5kW?U#@RUS(dL2iq483+YL%yhZFtcpen_NN0ay22C+Gi&IOp%=USpC zr2m5D@Zx^PigEtG>L%VXIDbXYec2)P?@cUQ)W1kGyJ2%m(A4h4Lgt9+&F+IP-n6a_ zeYLVMCuMowy8J}{n5Kuj$7bpmqz#nB$fI@f`OTxeM|ehLM<*#S2rR8wl0jg{Ilin@ zj1U6O!Bpr!XntZk5H+R;>zV|*$9uLdFLM+5)Z(W<(siDA8`rWA$k3D>*Mn;sv*Ws~ z;DglKMK56P>YU#|`QTsizrn5DVSW7RAb#pF{5bP>D6z|}P!i-?j97E2AvBN!HV1DS zyXU~GM>d|pCPf7)s?w@AKd!IHpL=>*dC`=I7vqBc-93EDV?ob71ND@DeNUrU>R~%u z_(gM*K$0I)bwzAm^6E4FyZwOsSE~ZXGh09aHbmVZt zt}A6UBroc93TImzSL6E@<9jx>qRRQ(t~La_g*sW&Ob6X%+(ryM)PJo!b%5nv+q@wx zEuDN95GR4us~80SbLg|+$L=nf>A?jQ`qTHqntw*6LsOcMo!-6X&ET_#_rL7~3T``~ zPulj0aa%?K<+%m{BJM(vS;V6_cu+fgB}hKH*&1Op1x#*oCqEDKUFXjCze3Ngo;H0s zK3`P1V^O0M1Wy~Tp2z7Ci!-p5FMg>k&|MmT@1;%aNi!S0vs9pAJCZ2VNS&<&5)U*Gf*O{YBi+RZ! z@4xCa5!2Cw)E&ki<2JG%xVR-zONV(hFb|jy@Y}^KUo&3}6I;@0iUlw@THcP}1m}(q ziAIj&0|P-*151L3g1sdT5}W*8xxTP3KKgn=Gd_LvKo=O8`#xE@=GV{mI!(@OK+i3@ zE=5iEJ#FaG_x4}>^gD-jy22+hlFjC(^GdOw+3a+ltPA7}MCRcbg(&?^%%j&z4d7Q& zNJVnzc^HVq6NA*nG#sn6#*uC#tcQf(y0E>MKUlC+i}8kGQlW zSsxC(;ZCVQ|6`G6K+cQ7xp*sTIfSodCT!k34y8HI)rEdW1NhUiIcP87uet=c+Rq8> z<2Wbbd${t`nd7hE)tg<+&`Vu4?r_8x$2>$2|pSmz-eA84~QxR3hK4PBYH!>m$~=BMw~1KBBvVd?oh-NFZ+Dv{pDV&R-aY zy1*u$G+Z0-cRM#gR=W-#-!Jopm5zvAW?_#FReMdu-0af`0`%wM{r`bMYeyCo! z{o}_T12M>z=Oh=xfxB$;Smpz5Hyuhyp+}|j0^eS}!e1n+G#D1|4yU9k@o{TD?Y&3t zA(kFm>;i~yrcdm;eEc}`b(e0(TMs`Ba>_7%Vp%nF?k3g`=Zqyd>;jHBh^P4Oc=PqU zkRSeV=f@YFCTF_PIdqr}1=m601B8Yh=L~R#3z!ljaITmqWccET5QwIn&zp}(#Fx2* zk0T<2?eOhdw~{Ln)G;WXm&JU|96~2?8P$X4ou+PzAz0f@J8Pp@KDV z?H5bNtkl4U6j|3Q1lNUoVrnN`zFc2j*?~8`bbJNVvs&o(ZpSNb!hsiFJa?LZwN-~N zR|s!UU>yxKYJa*Cw5kk&EMk5R!%@h9e0M& z>>b-|EiUaG^OVNRuB;o%YCC)KBJAfBxU_3*vxPa?Gv=9|aj;^zxbr9ZyACUJv|nsf z>~gYO%u_ID?9CP6MT`I4lT;?z%>X(ZYpD<`!a6qdi_J!{62)ejaK{5Z&~ZGoO=2Al z2bpaV^HBJT%>=Q7jrg-ToHL63VH>;9mEB>U$S8NVHn^}m;sOo~tDRw+q1bF+SP*f| z&Z-z~Jgz-q9gn%&WJg$sv$q~b8_#sEnd}DJcy(rb!LsNTRx5!!7KxQ|aBFWLSO>%1 z_I804NEg-sk)bxeB3@O__-0$cHn0|K0PARG&7b>y5~JXL--XU^8|;X^u5TT81Pz}% z51c0s^Kf)~+YF@~ot`_qohHxSyTQPeopek zSzou!T5hkWo2PD?B}UUjW)bNPmNOu77db9%OIa`mYCwHXlOS2xhA?e`psxNu>z=+w4Zb6H*5 zLfRkADl~Up4syXkceagGY|)u5go?A*l(}O%$W;MXN4AYPpQ{_2N4<-q5!8uairobcX!PW^!(SAo+6IbuG&DY?d@0usMe$83S<&F*h94;LNM5Si+TieLvEqbj5 zZmu@V9n0Z777(5=>9MxKf^7P$dAM)PTC07$z#Vkg0FWt>tZV~C0s7^V##t7rg7i@4 z4SG2!Ir5RuN`4nV-)}5lhGC2q!P=N6% z{Byy+6qD#-?tBtGp2u9E3()+ZPZ>Q>JD&C=z1-w3;L3mqxW&c}b41B@@-{=49h+Ov ziiEvgJ6MNvUA@KOZ2a8rV0KW{m~i`Z+7|yJIxq3WJHSG-ab2YhV#dUCq>Ip)0s$m? zWOAKYVVQsr_Tv2;ArPv?saIgtU7EZFN##FNjSqUUAAZv~yt`x4G zEQ6f&JbUa|Aky5F>_XdZiFbH%o?fA)ld~$d$iff^I zPj@sx)MI(?+r~>5Cj_|#n*rw-1K%$$q(u#=Nw*1mpTF~+6DP26<+y}N6A?IC zDetp$nwTF6er>!<@(*PYz2Ziaxs_qW$p-u0RaV^zC=bii%pS%co73wqEOtt-vnE*K z8pk|48?O==yoil#iS=pNu!bc^*p@fQrU+Xya|FIvxfxAjzSPw&*ie#%{CcZv`*1^R z=W83Skw?(f88_-eTSEKv9pf<` zVRmbJTwGRHa(F~?dkOWbcR*^Y!mC!N@Wws$b+x)ciFF;wKw)M&ioy%fF0>Q3n;uiD zjBeb{XR2nEX_0AyX-R{RwTc;)nIm<|661)e=~<}7}uzOT4? z_{}bS<-Id!YLEsgIt*jlxXUrt{i_aNo<^A;Q4Kyu886(YM7hQ~e1bB5IB0a@Q<7(4 z$ERjF3f>J)`XC#-<|Z_KFsbp`FRwm2eFBq*cXf221zlZKl0)vmtBcps9jkhnwHz4_ zcX5+!0RitZ;Fa-aUI_#U(mA+;$g|dzWs^q2&k7lv)oH<|B?p7l14TjEi)j3BEyBG$ z*UAK4b+x&k-eYR(8k0Oy>c;Yua2boe)2GkkyBoe1*EA^0@^U?EtT^NA7(RM)?>=mx zjLeDD2J{kRtfFcdz6FI;Nf!i@DdVz-wrpuxff~s^x8Gyo>-X` zUg+Pd@5#dV~6>dIEDQy0Ge>YG;RuAwct_ypMR z-OW-Ij8~+cUcUG4+n;)J`CWJ2_SCximH1w~58$(%KSVagz)3nCdX`!tbjoaFo$W-{ zTT@ybpuUN3n5BkoRmv3o?E12%g6^WcyrMIu)d6|=vlM;>Q{ifg6>ww@<|ZbNU3JIU z1m+riaC)ivgQv@?19Ju)HeRTyne@c{6I4pK_y;)3MK z)kz(c21CBd=?E|;?Dqz_dun9*y3Fvg4xk++ulD?>|XKaSPL$|ar)=!%j zUjViFq}Z$>Frb}kbJ{z;0QXpX$XQf^Ok`WW7{D$ky=K`iIphiGBieN05r+N}VaPG{ zO5ko4mQ8mpdw$xC;=atOb2DenO0TaILil#jgted28II=X#TH)LN8 zoz7odpP5lNSgAKu_oqLVTiCuoS+Q-9`|AG&Z@bUU)Q0^l^tgc}y-^M>K3LK_8C zL|L+;T@MAx(lk)*L&>o$H^I;92i6zJ4ikZ?L(;VzS`U#{1lFNUyA*iMELfm_IcXmR zYM3RsYTL(_ri|7-$^UA)Drr(uY;=5eg1QOcJ|inUab~?XBP}KY&4`Hg)Hl=xs-v0O zc|&r9@L)<C4X3G`U$>D@~6gf;l{RjW=GmEZP2 zV_Wu&vC*msbzW)Vyf}yno>PpS)SjPdTMBhHAaI$xFC7_X+aAAh#Q53E6l|lG}+yZEWuW`ka1b=|9EKg8_)k5u^g$S#aifPsHy+z@#6|+XSFF@`i@Jm2R$$H&|JvbC6Xeip+8b5lo^H z-zAWa{(b8@1j(}p6#vGL@|8J>3Hl;!u$-o<;?_+}jAlM!-#JN#V|v}qb3v=!>x}pwine@b z;VirNfM#wEe5Qu_#__xFxCNIpb#H!*u)fGW^dyy(b>+ z+kMx{=byhFzuQ{Vj!qn0^^(S0rImV>G%cA@UC}b(`^1=J{C$FUJ<0(C?$tww#-`|W z>98A}aa7Ekz;@HWIUIqkCO2x^IE(F>#~ymD6+lA7?0yDq%#1G!wrm(m(k4%foW62e zk_PVxiEU_z4Ke-3cdO<7K~lj#@L&CXnrp`9OUJnd$)gJ@V5kpYUwC18VO>??qZ#UeO)Gqh5+2!6*!P!Qky}W; zx~QR)iKJc$RP@KB*#sUAuPe)H!33jQQfTaoIJKb08PkUYAsHtr(B0mC< zBQ!LYl@oPRXOgI(BswdDAeAjv9l5g_whM?9xym1oIFSlaK?X==TM@!l3WT<#sFwIg zEN&|5dUZAOe)38DV^!6IGd49g3^!8QaZ!fbWeF-Ty)L=fKRHIN>+uiPyCo&16a}Q< z*VKzECQmBg^ND+YLco^`^Yjso$CK(Os3JqIc^EQ1{+*GZT53fYe_S1Yx%#iD96#~w zv*_8QM~%Juu;AMT!n|-_PpLRapBxg{DR56yNIWH8!P@1G<0|I7R-8L{>==5kC~;;) zM1J}{y?$=$0=R#gi$hWqF`c)9w+6cAKh1lVcNXp;vhF3b_#GWvCJ{aAXEemqXhNw) zq>uV}@U0M^+)a$^NGn2bi#AUaGFj;((8OyE%Vm*?Ug@dHMHXVDyCs^4@k)G@>0Q^P z+Fu@{oiwhznv%1ls1xi+Y8l0N5Pv!6Nh)&Gv7T4=R#aD+$&NptGzqOOt0*t;A~d&> zo6aZHrQHd2B|zPjkiag1yFP%WZu%(ic^uazRaDNL$&4o-;=8#V0PR7~;(M6Ck1~#p zgU}fyn>A}TZqe%<^h9sS0LtfZ3#rZ^Jv-p=1~PC+XtKFrFO6V-*@)zGU-^C0=P$qu z>kl?G9IVIVRPj^OV*ElQa&CUKj>6H* zn8eX%@@=r54XePkttJX&;sXy8nHV$u;B@#Om&T<|s7Z~fmnsq_)zcaN%Ce%oVs(&} z?$j|CVvy;pDXXb1n@+7{?oE%&dXSoeE9O_5B%*yBPXuwiNbqB&u@NDQ2hg?(vn_0~ zfc@EGG9Z~v#1p4Bm?o@)+qMvm+Q15T4IZOOZ|~G=H2SV~y#^N^C_mURe*wK31iU^4 z1U$}a&kdEf=Y>d}mo&U%#Zyn-zH3MSiAM)exP@T2!YtfdQ105vE%>obQ+dEwpZ^{s z3I$)R0Q?AE(9cs2d2XSQsjOk|57&eLDIdB>l!Nv-3G~Nla6i>7-ds2X$en6Dko-i? zhaaLvgGRuf1(q`byq|V|+j@h-t&Z>x7?BR|+y1tE*D@xVL$0&*5)EyO*?x6s=xSRV z4j39jU$wO{F&j2eA3&q}He=?{5Phz#?Rq&pW^HbTE-ahS+;-}V?J;fF>SEfq^G^&7 zUDvj?(O(Y@8KFTwb#222Mo7L&c?=CPSK8W8(9qDYo7*(B1R6sGHuB$0fH!gfw&6Br z2r50=jCXIxgWKr3wrkIA=a;r!*O?kdT#sr?5M(Co{_V9ke%ZEb&$ZEY+pZsPqvn%O zGed2|+ws!2w%rNTz_o$Qf@{Pc488&Wvw*)!;Qs9iylP%8uO4o3pAGkO%;$B&J?;Z= zOUJEJfJl1aR&y`Z|CkIW@1mv8#Z6Nqn9~OX?fVbt(QIv=aU+@-ldL^8jKAF+S?G1P z<{N=Gpok3;`Q;C-!e^rv#qT+~yD< zlD$=y+)>^H8fq)AowtzJf6J6G?+!M*mqU~h#FT6Fo01bEZkh_Txp^+>rGh#v6uAW% zb==f|-=IYPSFruAwHFWi z>W@b?PBFLjx!GfwoWD21HIehKr2GKfUVW>)&E;p4upN+lv8@k7{DwjBF>Ct*cYC3+`XOW!Y}ufBjF_TxgA5uQZzaGg#cA@0#(x zn`ZMH%5lQyxh}OB=qdoaA9(bpy$Yt>MlQGiIUG)X#P*Uy7yk@gle|hCcGC#Hk={bQ z2F^B7H+T&o!S)vM>)a9Vzi?dAGaP#Dq53}q?XLRv{gLPAA1h-x9RvRhB%qAkUWDk( zpMrn8zJ@oC`5XBKh=t_rv+UsYfQM$?E$;y07qBHfL0tDgmG9QPW^<$Ku_Ed9T17;`A@rZ)^t*)A5Lj{OIF#@s;lMpS`_jO|Ji#^dJ17u{v*zJ^hcii0CA#&3~$#!Va-&nd1pS{`B;znF< zJs(=Q-HQS7qn-{ow4XWTdFRgIOxB?)^s@cLLe&bPvGr?+`EKsp2cs7^Kyu{ za5Er?HPH*2>T;0%w}^9+4l?qcMI8SBbEG}}7__SP_L1hMr$evmK@V^DBE5d`UZv10 zJw5@g`*UbQWhT$J+?^D=Y~a$v$Cw`$X0N;W$nigrMt`Kg+S-PT6g>R-G?Ci(@}}PY zZU^N;I2?j5|}cxT178u7l4){=^*n(pj`uEtHNqQN=yO0(xr zY4<2ugCxhjW)_XzE1Nqn5#wPSntlm&Bq5VS9FR2NJ)Ug8_uOxoT&S%RkO324I5hDj)W3_q6E@fi~*4YHx@V}PzJYK!Gr5kS;BxU4-XvrW7 zw9Q9<`R$W;ZYW);o!@)s_xKHzJ_r>PZ<8O#xk(pj>)cYmIHV=Uo~1*aUMSG=H434? zl=WhRU^DY$%d63A!ity=DJ`x-Cl=s`^Qm66G3N~aH`6vmU))?=h}mmzYQY#o43xRyuEvw9DK=8-6x7g9-ZT> zYg%XSsD}$gAo16ZK7ml*k;Z{c6a_7aV81{y89+hNzGNSgS7c;ULSuaZ4ldR}N@%ig zgYTWntp~ULz3i)v%M0~XM8e<@R?W@MS$wthi!GBMo;H7ebO0`*;(e+Xq37_wCsaH*t*M^^b`8jG9er4NR zum+*s8oZ!FLP5GISn__GV#MEd=i*E{*!IpbF>GG1Ebuy@9AMj<-~7*=htkb(V!Z}*A_-Ub;* zn1?*rW*o|0^7?l;ungUEDRyydYuu%3ylowRX)-$cG=3d#EJlX)(My}BmEC(gUb6P_ znW*KJ=Fo9yM}7B{@C2y8v2JzROOnO0{ zu71+8=|$7#|D=x|2Nht6dbsj{)JSvXK_ukT+A;-gSR(24fF-?(@R}CDhr~>|jpS5;N0|n7 z!8R^e18x8TYQkS8u>tsi96n#$N}sI4MK#e!?tW(mdaD+M*~>lxhT->On(u}_#a$H~ z!1L=~Lnq%ld1z|mNi^6x?ThyIYlW?N6QQB~e)EA$^Ur4)Cx6GhGiPvd=~F99*AyMzT)X_B@l;#Qi^sa#YmWE69rx7y&4<(8Sp5Lh z7;^b847yy$!%ZQ2@RrzNkb*4)_#pPIFq68P2Jw@!*P?!EV38}vw4|0asV zr~cCLAQH5pcVB%Kr?mar*x5;c2F2JdJ;`T@`?NhBg+PJ%Qn&*CQ-XglyR|5J(SUv8 zTjR#@ZL1<3TVORLlCLNG!z2{oRZxY9_<+Vgq&mzbA6emUK;|t%9xXov3%2z>{KApz z3l6{ic5U&vj~C634W~<1y%4A@s#{Yxguic3ojuKaIsKoU6@yCD+RYVRn9C(x&{|RLo20i`%zX(P_L4(*4M~YLEl$`2cDyIRR)tAEZqck**|!i)p_kN|A2Xy+m-llYV;Er3&_4 z&qIxw^$V(-KCRKWCX7Wr%XTh^?DMTyc)6qFr#qX}+e7eg9q7{z{2LPC-#F`AKX0xf zC-uQ8n=)pX8pm`aG#?4H6vK2;I;O6VLals(;xPV#&bhdF@jq{epozUaA+gBuP-S6T z2az3waZRd+L8OH)7_cx){)~;%0(E_ae|&Y|DGS0AIiN z^vAjHJW;F9Ur@ed$z#Dgls#{x7ZxoU+p@H5;jEQ&-gyO0of=m2WJ#@GEMDZTK#!(A zxQE#@_uZ*)%pE=9N8$5QmMltc4r`rs$GE%+6JPR}Lrdq~ zE}IhB+nKW`zohCfSw9a;CVFM{@2u3N`^RWn7q6bnpZW7}*&Uza+IwS}nN(4Q=cIb% ziL+-{6H+_ycNE-lln7N@(5uNxX_efp&zi^yTivAB%0c`?c_0v${Ltn{8y22A*!hyO zaG8pUYd>@d9b|ssZ)d(m_aDUH;df9fey4+I)c6hC>L{_v`r=PYw5}57v%3$bJ0L5oEc!4S^xdccQh*&Dhl^WnyB6DTrViw2UNMskh z%i(67Z4svrckDkt^T4Ioiw}H>9%T+QYmsLU7UQ44`6jcsVp48vNBz+MC+e<{ zQO#CKtFo)ME^?7&TkcJkqVI_-Pd{b)p*SMj?(NAD;t-N z##_+ht7na$d|Su*&iO-pBd%(`EMvwfLhFV8UM9Q+(MKtHHNDSWfwt!r;V8O@iGet} z2NZRH;Q>O)n}oz~D+%_Id5wnmKpqu%|oFM*R4E{Qcz%r?y^s zwqp-!T!4eqN@GV&npzS5gvu^#oi(^~)xu7s`%`z(W!Ja^3kj_k+8wj9x@nwl5{%aS zXjZIhWTXJs%G;4XFhbEbOGXaRbX9q3?V7l3;IO#t#BES|B^dTAj6z;uQNOn9E!*=z z`75Zf=H)vc+-GlQEi>mm0vpt1OrBEio?1R@Ok2G^qiNdmJ06aSof62pe_?56$>{c@ zGbadkG&E`d<))FV@V{%qxMQv>e_9#7RT?^Dh(sUxN=hF+vyWF)=7eqKtqtBO^#^Wm zbtgD-a02>#@rs(p@;2MwZYz9fOTMAvmg4VUYRK|7uj%R;GNGlW?r*5llh*j&k?rAg zt%nx0Ox_uDVzKM;%bvO|d;6nQXKee-o&i2RY}TZ;38Md`(MrGr;=ek0q6MV=D*t_Y za9{5X^e4U=Ey4fFx}p1fS9j76-RK>hNp{bpiuwrnvI7-%BGZc7D&9fWp5j%cJ$K-r zJMpVTju-mj#GaJF8$9YNkSI=|n-QCvPJ`Ym!cd$AkY9;J17c2($h%-uLl5|##EU>) zkQ8wlWcVi@cOTwoVuIH!pZh?==?N1(<&Ly#=H{Tng$Y#`WoFtXIK4Xj6?$uLL-=7l z3O)4C)Cb!3XJ*l39`V5ZH~f&{OGeKe zG=yH)jlb%~pZ4L;oNDgqXztj)J)C{nf{Xp*3MS9!M6>bFx5Li>yO{+06ZIdDD<}{J zfi>CW4S$aWn&RTYgQ3B5B|?$Gk#p$4SMBGVHW-78^33?=>Sg1*?(Ie!pES;=WXd+` z-1>?5(Q$vyn$k_{4M+@qd~ZJ_-*{}Fck#57i!1Pg=2`Rv-2Mz&Cv>k24WH73hT(4> zn7ZzfyHSR9+_0v__*OK5iV6Rd=+%Y3sp^SkgQrd6q}uzdeOxA7gnzL6z+upS<=*M( z^UGB43_cag(?|p_m=;klU*x+_3|DrC+q==_3((fF;cPhioNE3B1w#*w4c;{LGNz*b z&VLMjJ@mxz$ye0xr_68PQ}^@#x6wn)l2z&vc(Wd9oib z4z3H+Lv4CAA4#`h3^wOgdg;2(Lx+ky74?nbUrO<;>|s3HL!lHj!|9ti4yARV82rzU zP=$ZZnxC({@@M69fbAFhX#?1qJ}sWxdk-_AuXdUz=a5|JPpSKW^y6Rv+RwnqQhvxm zf72W~PB+}uyOg=A4_W-yP;jMB=jaotQDU-V zA~9+_-d99|@ElQPMKeqC)!7U1;v(Y?C+M*f!t`tH+LPiVKok+W`ceM+dqFoyACKQ>9c&5vlGP`x6JCULAG8ZhkZo z==RR=xk&?L3cK<|c?a@P`f{Bbk0IWT$_YsB6ZXBmXVAa#M_q@eqtem%IGW;N=5aC9 ztKpd3MCx69IeN1Xb)@S=TVK0lC=$`u&ZC(L!!PN4YM=l$GDKvO`r!h$1bPGy zPkIbLtwj0BWgi+t7vtL&;oIoN=*=ZGI-}g(+*dPIJA=4CbE!)ZhtJ~{GzdRQ{s;QL zWVeET8~~C*#w556su77x5kAlt)V(J>H+ML-vpf7OH@jx(Km_jaD?c(C(Z0|oN9a9ku`Fk*#y z4xVs3G6e(Xoj6#^q#jA)AwU!9;(-1A(0mAg?MWSUSMvTKzJ>ZKJpX-tLQ<9^JG;(z zQ}L5c$nxQbi=KO~pR>q(7}{K)Q;4Yf`Sixl@S!pIx||drg;1v#6%Lv*j`UWk_`^>8 z<%j`en}pR#YGFs@0f75{&&PJIC8|f6#Wo7 zMh|_h=Dnxuo;Vo(WyXCOw`Pa`#atV9T?w;0Ki}3T8~Vi&trwp=F=6J271wm^+0&8j zxto!e?s{nnmaJE~4ys6}<|tri6a9?A^TJ^ONbVF?ZjMY`5HU>bpzYIzA1- z<{&263*_g&;7WE)A$z9u;R^gGzZ~-E>@u_lWfn+l^)w*aX9r&%-neL9?a&)f;kBdD zvA5>sbl&~Mv2ZhWaQve1EsN=T`0R(+?r8}lhgA-K_(vR?0K<;5VY%xszhPN-=$qE* zlmj38>$#I9pRBOpQHLV5SatlPGu+wL3Mvb8ec$*a_0&W7hkj&!*AjlBC@q_&I$7jKXYn5=@eNg_Xx2%j4_`yQ z-_p6YqZ@uYw(e-?s%sdGmyGHeRo{U3;r(|FK7;IN($=j5`X@5hf}K~R_KJ82+LWvs z!h#m2BeRQ2puj^YyU_YR77BT6)D=6I7S)Ze34gIT^<_Bkpbfu)S{$hh#3br{{6+W+ zDjp8Si_TXuH_!5fQ)etR#9f15r|z$QV-V8!b{5SY85cBG)LpjG&aY70HZ6ci2_uR!e8GVXVs6I5%#O@^=N=7l^ zw_4vsCh7)!i&0k zH+Tcbx>0L4YS)KOpmq3tFi!7uzxgIg!5^dX!@BXrE@}gO_9JH8+&ClE1y&3WWlyDp zhZisYVAZPd(wReM)_1nHcGk}v65ik1itaeO680k*VBfr8+laOAqe~$}Qsd{5Ko!g( zs&Vwlvmn?uAObvZn76-xlnvdXM%cTkvTNMR=Dc@P=d?_#8@hdBURT~Ql)Qd^xV{H< z+wf^Bgb#@5_*3DJDNjpyP#-DuQ3%GGyGK?xU6DAgqjdN--=(Xw=FRTyZEHjKk4HoB zW8+cL3fyuP%*I_9$4SuT!dScHFMbb|jbQIC#Ug`gfg?o8SQGYriW(Xa5i~Lg*+5v< z1w*Mk1P(tK6{j7XAEIJ?a(Xze`^*v;;k}1;bnhxzUg*ZHZ#}jMkM278EAB$GGz0gWRiyOzW5---GaA_mxtNJ2pa8CSs64Y8z( zv6LvJx|?eMY(qR`lM(p4_;3SR8`6Nr;_pVkzUbny$cex1#{WjPm3T!fn!f@srnqiO zhu2RJeb|5xqp=P6hT*q+FIDY{hO;_qi-$xNZ^T05(8g{55y$Zt4&izq_>U<492w4G z^M!R2|Equ934Sdhh#>72?~;`h@WD3#(IXr&gaGEPSzYW{g&2 zq}33S*u5Ojz-(JuWW@p*R(gUmA4Law)QE3Caa}tvv}Hc}b|LycOQmr$s5%j%q} z`l)d`63K#W7ieQgxEE~=ok78Fid{W-`nHz4!krD>lUMwsC$saSxj3MaL|N+}n0eTr1f1ysF%HTIxS(7NrtpHw||art$3WgJ?PbIIYP+t&Iv;N1Q+A>s65p~d|vB=R!$(|s5CgV`Xf zvc3ppv;``jJh&g=jYG&ivP^;O{0-w&WoB6M;lT}qSexQx(GgohqL4}u7QQbaxyR&R z5+8%RbEnL?$2;3awGGCf?_UAt=A$VKTpjv^o5FkAYxlKWO@H5OzL`F@C$w(mzR3^F z->0#FIdEV1ya2th)lyn=rN($D=T=wD{#r+ z0svE0V+`xDzznFLPBM~G`XAsX=dEvV>-6WtNI7b)LpQes=Z@>5wlsPMTMcPT64yJO zLn;$(PAh-MVEjfE63QQT`s*7q=H{?t2XCZYu_MOLMoo7VAOFr2_dQ~5%mT`a>OQm> zLa#N1ilV$Ou=BBY6Jk4ZcD78rXKwiH`t|FXg{uZt4qp=AJFLImf3$K&b!B7tqE>tA zdujXKi)p7czG4}EamtL^ADV0_6?m_&YC3c>!JDRZuBy9l7hNB&UewT;RNXoBobmJe z&f0{|RiRJ%ON4sAHlabrA5NGJ+Ph%`+WO|3#1-r>A0B2U@}N~#M)xAotc}v=DQX)~ z_z1lp;kn(V#F@Ml9hpJXxUJ2kDceGmDH_$GR-NiTKI1PY?q0HW-N=`lrX*1@{!v&! zzwAkEjN@a_qKW#go3Ly0$oZ3&;vpIbDSh)j;~%M_-LDH-*(q(|Z-}d={$HTMy;GYz z_8)0(x^4?~;^>HBiTFG{Dt!JF+RbvCHg@87F@D}rx@vHB6OQZ8qjwHm(z^6|sv^Nu zc;&Uj-$8De!MX0bFj)yj_>_$2@Sk$&uuC%WmOaqIYa)9z>X4}OBs_z3j&^TJ0cShIotMm5d~|A4Q@*N1-qS*=rA5jHS~u|>LK9zfj^BtHUD#a+_ef(?hQ zgZTT|Ux5-Mtm=tT)@+r4S5XbS3h0nGJuScxdAi`h28Q;Q=z@sSu@bz|1AZWJ2#K~k zDcC*V0}Di8tOPxD3Ga25&|qfB0_!Po@X{(Ju3iFh^R9SQ2-lUAe|keOX)uFk{~hwlmZtNQ%lwi z&@f1J$-#6_GFd>Nc*P{ACpic_c6dHEmn(41aX?q1NwU+2{-3wLWw< z{1N3P_b7;h_+ z&#D5v3~#{83Rd;B3~$|w#`aL#>^HWZIn#EdJ>1h1?$K_jZNH(dkzA)kzoV^@@?aYn z(4Ae1?zq8v4uhRqL0_me7~FUx5j<~6FhG|zWw&hODL7WhxxI+ACKknVP@L04sH#`krxz_kmBe`pb`;#IN;?>FF8sDSi!KWbcr! zyY|B#d_JzzR8e8-jDxkXA6|Q%)L}=rBM8%&qV15JuScR++TORTbZc}s>Fy*}h2~fo zJNhLE2f*=aFvd*vQSe>`td%4;;2gl7De#z)Z74wAu^>ksk?jSbl@ftS3~02UV!?R^ zeu6SX7o{vdgijcyf`bsbSKI`c=p$gAkgiPpfsukyt6xf08VCs;lYkO-5 z6+(e+S5sX8(F2gd7(Vl-uD1m(TYx{eSWv0q>7g&-YoU4RlS7X0}Fw5+A~ zPaQfqnWiVxVMpk#S7(N=S<$f_t$YjLIS$|X7FxNzV@3FynXkS@O>S+)%bQ-DhCiJ4 z0=h!EX~I3NthuWbO=D-sni0a>L$D! z+RTga*3Co*uBFGH`sjH0-QyoUb$lt>h126iiV2_Pa_P+DRK{^SGj|0N!}ksf zze|_lLr;cp4&N&xY7RcMlm2&2*{VS$^=`+~r4Dy}$)HtbIL;r~R9U&{vE{2==;WqN zxZ1U9`C}v{;J#9|~YmXOGzwc}u5qk6ZX4ST+{nGfz{sTJL zAl)Ou43`tEhU6ig5X^azmH_QQ2TL2kgakY`7Ia-<2Lr|eERW=|>BvGT z+`ua;4S0p1F!?1D{Up{z!!>_D6@CI0Eytnmk;~ARg?I}--!!_pd2|z)&@F}N%Vi_G zacDUzf;T}ZYA}9fIbt9ujw?hf5U1uu99mI`;~*zumg85b!BlwA@t)(yd*`Y`VOdTCjQq@bOSQs$x|R5B1m$_!-Cx z$2ObL4MXw2P$sDGJ4haiAwG}pfV`;chVT$i_&53=p{*XB$*^C2p0SbUB5(*v*7w2ns% z8a8Ud;xpSHr`Atu5Bk?^dg*W7J^H#SPkxh=KV(=zUZKBccz!l|1OIyF`KhI%Ga>2b z&2e(|led43s((dPf;TU=vF#Wv>&CCYxpMXKt8KPR_iebXVtLP!*RJ1v(exeFS8sT2 zADZ1zR#{y>yso0Ax>TpTRI#z=px@`=eUVu3Wl8*mL|e&eK^MUu7Ykv>q_w)Oy6bg& zz~Ua#J)(P3_pI&}-P^j4bzkYe*ZqzVf>$;Xgr!j?@}mkg7>z*9aAxi-)P#04|9n>M}2=yfOEOnYXL%mO(rM{+qqQW#wn`tMV0CUXQbTM5? z*V4o3adaC!gPu<>p_kKZ>C5Tu^o{gw^gZ;0^l|zm{WAR){So~INFBsVX~S8nN2Fj~p1OAfu6^ zd3|9Y#iVxd@FB*Y6)q@>DrU%g__`t6jA(?$hDTHl}1`=?E$ML zlxQh^S+#m1;0cy0HZBz}rz3g+%!0>kq}CEygQ@}54v2}?AFU+TNpS`z7gv;(w0m62&BUTW zpyRzBqlgqN$>!`1j^b2Wo3a0g@Hif)MTeU zJ>BUC0A5=Wt_fC_J5#3y%Dk??BmQ8}|6pEWVcx_-S8_=q-d$c+Q3}t>0*?gX=Mg{r zv;|;L1ee8LdtrDpf!zil&QxUb=NA^X7Zw#2w&myN7Ea8}%gYSCM~G+(%Bg9tATp8q z+l%uHiyp|$%gb%g&rgL8iIKL(150_}d6C+J5D0)>SET&8fLv#_M35Sj9FbMx?xg^o0MY$COw)1=twWUn_l z{2{r-Ba$5c!obAByu8APN&>-RWX|^oa@%u@inG~gexHMKsWYgV8hRd#1my0`_xtnP zN#;ih%O53)Q?ub`Qj*=CSXh)o@V}U(a&sE+j}2&d!%Ynj56WqHpD=QY-;o4750n%K z@%L$tLVxfPkIU~5P9=PKf&dKtJe!UKYJ*cs0)diarNOci9P~Iq>{AJKC?-`7!n%o> zgm+I6N<)t(#Kk2{CDlGPn;I0bdp*v;v0yOO830L?1wwOXqcz3;Lc8}EJP4FbB~n9+ z%L0KiT%7DGEG(H41Pt&Mvmtar_~$3$I+o;eBtX8HvOq9+ELdC|oKgWGp-2goK#LW8 z3G1g21q?b<@V^y&D~e0Xju5oir$J4=1ue-0RdOb$!`*c*54pS^5;s?r1@NPgwh{i5 z7X<@wQQ^nOoat#U|0j^P4gN{SZO+tmJCrFZk&@4X8YefDl{u3M+;5AD{h4Kuoq$M( z(j@Vl;$nYx1*r44g@yJ+v?l^78NUs9Z!0V;yt1e$cWZWLF4d|$N|9Yj_y`ob#$Q-? zE;Bp3sK_tH|D2SRjE~tIc18!eR3ZT1)=2rQAm63%lrlj3@CBizD38$1gs64^hL1rF zXh>O_BY=-Wh2bwC_Z*KW1ucXNbkLDj;on|d6xa-O<6}@W!Rq|0)IPKd=TrM{f=oZ; z`|}lC3AheOs00-&vL_|ka~16FgrvfiD_>Z>8qZs~@@3_3<;r8glk5tpHa!sZZ*!yp ze_h^SkZ|W4z?B-ZV@LQpAc=66uni4YQ7QJHl~c+BNlPQ?)JO5Laf6eSlWy9v0}roA zwL4QFyDCKr@7NInP9z?1rV}y%zo&t4G}Hyvr2_!eymKe4aD|KEh5r1lt~3zGXOQDt zz$ueJL5-x)GZB$xy1X7&FnLL&YGPd=4uK$^bBsI3o>ty8WLOc4 z2LJRL-E}}V5XlF9a!^LRtX}bHuz;7)2~+}!5K)PC=g};r7aQ0eYYThHGtxDaZd&PM zBiH0PN!Olh&saz!|0F;8=BWu(;pB>nNdXG)nMc)k3?154ONYN-*gWjO3VuZM@?{6v zgg!I*$D|;YT9%p`$e_7-{S4qEU?hz*3^T%+lvCOfT7uxdt zc7GMVYe0K=ef|2^SFXetuZExF>(`@&p#8?xt6x_BRJ z4{txhECc9ai61VMCnN#X*Fz2^CBOcnL_}2BQ=|i>h478~%NFaDVH#0za_%C05Os!! z+@-6GiK`zjnPau=G2+K6QtTBXda8UOYb{^Mg>NvKIgvAoG0)k&$(+E&aF=sFexfxo zVLG3`bxwBnEMw!IM*lb7k4y1b%6%MVf9b4-Owo!N({^`kAudt@1*9PO# ztE#isZZk=h#f}BciB){!s^>H7ObK&&l=viPdXfqMoK!3(Bo*7J{O4)-72uLItjf%kj)v+S)9)iuF6WiHqWG+BA`xI$T>F%nKKQY26kEb{de zL3DdHmC?#4Oh>3pClLglUtu+QcZ^7cP?= zh_gP#l|S`V=!N29+O45e62YKvT||1_fWQWRQBN~sB8*l{NsDQSh|9? zU3%g~^8LK=Aj7oaubw}Jzv`m?IiI<7g(ZGa$(~y!=2k0CYmz)o5`M9q8hxVonPgjo z$xDljbSr1YA6OG1=O4dQS6;sx2HE(9Pj0)4f{?<-a_2 z*OqJHydV^CzsIjou<4ic)X$hRRb(wCv?nd2hy8CrUbtiPs>t5G= zr2AU;ldcyg5lqMdEAg_G@ozmEh1$>zc>i=UT7@>CD`E6|JGvJ=1PA;*gI+{$pbyaJ z=zH`#rK9weNX1aeR0dT*RZ&BzQB(^xg_=VxpjJ@ps4dhsY8Q1Yb%6Sm`X}{0^*gPj z^|VOG&=4r3bLavX>y|2`-FkW$J(6yso9RgqxSK}LqC4m=x`$p$ub?lb*U=k6;+!%V zftCP4G;Khl3{l7^h>Tf4#OhO5-(z)T7|9lSstut?8B$gq4-w<4r3}oWjg(0Gf2pPK z@jxIN@Mv`;LCLPv4CF=e|6dhV$?ngU=tx+rO2bsr|Cu*% zPRfYQwlYkco}tRhD}$3#(>0-lS*Bt12qntE#K3CS=Ce84S#LR&Pd= za+Y0gv^YHn~iqu%yt7Jh_GvVjq{DOjfB?rE}GA`3#FpS~_mMN{MDw$X|Xi(Y2 z^muogLC=q44My}ZDbY^Awdd#L<>KD*s&u)0VwF2R#^H)hZTGrs%nUb{W-aJQG;3=v zc-Z*7lC`b8uC5$F#-|$%>^Po}fILD*hiwEdZmh1VibD{7`QRKk?#i% z89nfW_vZKu^N>Cje!@Ril$OZp6TI=jjrP>|m>d(&HM5+c;(J)he^X9=Zk|%b{iMwO zi3tgb;rgob%8E9qvAVscRxfZ(j8TuMoc#P8C1)FL=Q&Ejo`Q2<;*X%yO0nq86H%bCz$hO?>NHpiHcDELj`Q2=Fl0$gapxGv;YM9 zV)}xQ*gt#&D(u4$|4az(yML6B%Dw#m*dIKcnI7-7F^t~uPFY1|Qmn7GCTVa+yxq#N zJZE{aqO968Xi!yBO!i=s#Ihn@l$n|32O1#^5}W2522XJVByEGFtKb_o56O%Zt*k-M znqDO!YoT~tW@ent3J{^Zla!CbsEA4R49bdgOP18Zu~~HvI|OVQ3EKu{>H{OPoSqS} z3vz5LD9R;u{t8H>E~}`BOIba5FsVn+TB7yflfW?41nA+%f!SzcMMY)mkeDomDqoyk zWb`c5=m0pMX*mhdvyl12#KZ*30aSPf5xxwzTR4v4Ecm5J#g|74RcLva04BSEX{%$h zeL;a|XdAXe9zw5*M~SN---%z>^1CXs67zkRM0ht4T<;#$8Asn(5);f<8=w>qKLbBI z``4hMQUkPT*9kxd{>T4&PJDCJCo(8IwWYx--vF$EXaKM1BD4+8Hr@wQ#ScS7|5@}3 zMD)*s_cB58UKUcTs14Ls>N;vKbtgpZAEizx@%j&`e^B30KS$#A33M)9MUSE{qPywU z^wsoU`VjpD#N|JtKcl~(e_>e0z?d0{@i2u<9W#U(&a^U}%t~f8b2YPKH+AVyapP5pg9oo1s5=cfkiAA_!ESG zeMuJ}rqly~wQsdz1u0Td)Im}mBA_^uSM#F&2S*6NK=A<@2q{tS@S1W)Q#7^J{1u|D z1gmHU?EwPdQQZTW%7kP;>GW5*sM_><9@VpmTBQwuH}Ls?gFo>3!14p(55zC(nEe+# zNIq>=<-hS@AP!pDf#n9~8+cF3{kJkv*d%Y{UzzoRYZ59V*EE05nl(5xF3UQ(66R?q z+kCOgp%^|68wuVro6OnLMi+_P%Vjq!%`HJ&XiL|iscOD z=(IgO&TbLy@v_ZOQEirDVjbq1L1uD}y4hE^5V0m}MU7w0SW*)Hps)@7}(Fxz8dC1Z`x=15BrExhE+ki=}K#mJd$ zX)fL{N#?DRXyROx;`LVe;pIsQyv1s@iwjvzeBg zOkzQdrOOl_W9dK?gJv0%va*tlOZ5hWekb|hO=h3ZA{eZB1!nN&oMKA+LVa$x2iV~ywkMc?oP-S~{MMbqDpY{?twW6d|$SCzVttJDNNl?Iki|lvD;)O(NlYBA2 zxXc*eL**3}s`hd`Ta!?rPzy$Y-y7U3JVJ+ z=H=(-wddsK=1k7dE0Ej|5yFm=5AJ!h9=3=RdERQ1#~L}KRkCshvqQSe$eDoQyxwGU zbnu)gLb~4KaCDpWW(W9ulH_*b-3HDK9A}|`?R9u5*=83FlEazU$}?t2;tdXmb-$i7 zOE!tqTV1v>1`v?d%o!~<`wODcA~{8aAj&Sh3s?ryg z0ESgG17ebWKD>@=lb}vfaxfE>xt`v~44f#5B4?EB_Hlrd)oKAy4)H|`z=(H{Ccg?1jy7;oid_U}SWK1dDIyWRM6M(YY+7kcm26(PGKdbZ2up=5Bww-< z(nP)9Vo#MID=BO9*pxId04a7U#bMz&6Fjwf0WT#VXBY#m*kZRC+@YKN@v*5EDlIj| zP+c9a%*(StyWlp0LQ+R-tK(94)d0^z8`Hssf`4k4$Ln;W($ZcJdf#f@2>N4MWQi*R ztAl9fg@l}3&%a^J!LHG#`}iIziD?C$R$E1d&1!X&rOKcV_Oc2|ME**U!>))J zc9y5fW%s0&IMR7f`0r2?x=bobwB{fuhz4Yok>~ZiQC?ngV@XN*&XQz@GkLQsRk?Mh zr7kKd@%!ywSk1FA5Gc4hFQ@QIz`p>#6HfyuAN(`46yvZ8MyuU!H8ca(FfcZYpqS8H zEG8Bji)3Y{TSbT2U?6srpJ#Ic`}Gzn&SiVZYPXm<&SV9(JMD~)i76b*hQltL04copSyZB2d`g;<2t zBxpl=i1fqjT1ZE82{5xt601=#71s2n!%P6D<2g!>z~VoMK=WKA36^A+R3Nev z6ZSzP*-5$$K)`PW;*a7Cc!%?@FaDKdL6>=wl6S(qk%@X0U4CK@z8X&3`esH}_o(sL zjQOJntwGytQ#U16K84p!nvuseS2{{IQ%;mKBw!W)ja%o>)Q=6sq)$UD&b0F*+RNjL zSK@S&J%JihbmbK{#T3o*jA1WfLoefd@a=fT+S%hL9y%}y-GY+gjphLM(CKaXOMDJr zd24gmup^&-f3oYd+IR69Dqb%I@N@V79e*=o%>3sDcOeU!7sufT5&rS*XI~#bW#{0= z$B^K);_rE|kM1unPOMzg5^F=1yKg8mh_O0&D`6bo%74kl!TgH^E7;wUcaWN3H=s7y zHEq65n?2j4%$@Dh?b9999f7#^Y2BN!vP%cskGft_BA)7_h93c zhVY#&(Aw?m+uF81Z*Q6Qb6Xo;FwS5?0(4C-q;E00U9lU+kEfsRJWPfmP%HoUdn(Mp$1EH9r}M&b2S>GBCMeON}LRe2~i zHz_GQojx^%s%R$9>F^tQbV`0wQh|r|x6{RBqOp|9S;iPTsY`@0=~G7e_|#;5c;nCU z?j*}L^zJPyyiMYudtcrb8g^~?ndfb3nVIR*P3Xq)sAce`U5~vpO}~V_;*aB~?3U2S zA1vH%Ns5pExiM#%-;kc~UzXEIUB<^HvU!ce^T%4kYkoB3r092|4{r&t{9qxfx&^21 z772 zbFt5wn_E8yI>0zSP1S)fRZw3qP-YKYGhKJ z3{{n1qMpR)@b`M1NmU$QM^CQ&y$dB=v2ekCXwxV2)?{YqvlrJ0L{F71q8WG$4Kf((4X zoaGuTSd7WkK~4_bJm=#dCgsm+IJj@*w2iQia~!^kKgot*g{uK(1E=a{!R|^I>o)54 z>ORo@OZO{ckpR23=@3ocr=#H&ZFqIXA8FJi)&VQ1puwm63P>~0N6PpX#@O(L@KL=j z35fmfNP0CQ<6!b)hmyH=orr}zutO?YFb|ufs=vghLp;C(FOQMmh&52IT`*&d z2o$**7L;lQs$tLsuSZ6TlT^v3ROyl-FWeLHfxt+b09Hd4pr3ZhAZQ14BM||U<^P`r)fOUW&~waEzX^V7c$l;5^Jm_!K(%!d* z-LSAJ^=i}P2|4D9c6QIwFFr&k_x_lycL@f`KH4&**~k?3e%zQ=BDjnrVtAG-Y&DgR z_t(r`lEw|~eS02re>oL%c{(v!8CsO zswdq>iZ^?nTeKpRPl*fLzue#}7)jSHb;h!F>3WB)0RIr1m?xyjCcVMMoPXyO7mG@3 zvki7jEE~eNo!$xiK0n!72)jUC^V8bjzpxcmiK53TPw`ruX_?Y}3wvrS{d1k%HQlQP z+ukLs=}E_y|6y|@YR#dw*l40^W?j5>T=nHlb;a}F{0aTsjdwq}49^ZZZtQ4Wg3mYO zbJV6M!i@&nVDS{^cT!UB$GyLxT0?wdzF1q@+Sn-O8>-sU3o`TLn2f~ZeEy_qr@e!H zzB;twVdLGKE^tYt1ixzY$U5rVJa-BvV~u&)TI^tqqH(HO#qb#9DMGw4ZJK zhnyQ`d^hW^)$P#Tth-BhSof&zY26Dj>-!$`kDu#))cv9hLrb#2%x@yRwOWA6Q9Wve zmCx;HCTw=ngO;F6l(o;-q8nlUcR#uh9YrUV)z9z1E7PB&f1-b*pV4^=Q3gt)VyQ$b z4d#LKsUoVJs-+sKW{9QErMjtQFcZ9$+5xfD1JwQ0G3puWCF*VJJ?e8MmWpW(W`yl@ z9Gyz%(E+*!W`f7k?euJz|6Kxeznkf8^lthN`ab$7{TTfW{Q`Z4{*e9${Vn|)qhpMW zok?JPOdeCp)IfxF95b1j!}Kt#Aj-Oq*~(lGk=DDI`3I`cmB59V9uca~yJ zti;B%iEIX2$X2k`>=1SoJArLwXR;k^54(chz+S~(%kF0PvUjl$vX8URvaho5u%EDB zu-~!2a};ObY@C}*<#MlH1Ac;r4U)aYwn6-1FRP+`HUI z+!x$;+^@V2rji`In@{Hp_)@-(AI^{E+xc017r%&K#c$-d@;msw{2ly3{wV)6|1AF^ z{}%rV|1bVWzE{ucje4g(NuR0r>#Oub^<(s{`kDG}{c`MtzUjK(aWPov_A;yqm$TAcgstiL7V-1rHvkdbLOAX5n>kV5CI}A4)4j3LZ zJZ?B;c){?7;UmLWhVKpMjjYjPl#MCIY@^>;W~?+e7@Lf3#+k zHkz(B?J(VJI$*lj^q}c+(=(=*OmCS!G5yQ*gQ?fdnk{CRImzrZ7nsY;gUut&E#@ia zIpziCi_MpqFEd|h-f7-r-fzCo{HXba`Ly|r`7QJN=FiRFn13;cEu2NP#96!+pC!*y zYzbOwEJH0#mR8Gj3mp7{JVC{A^99Ja7u-l6@A1KB&_|p&Z=i;_ZtACc5 z&*xLhNFJF_LS)IHazP6CiAU&{gFg88%RX`oiEyoE^h-Wo=KVn@)Bq)s7koxi8(jOm zaxe+0r~r(76tE)VU-C)@nZSWd*_lrfWZ_l@50qTwBlSVwJ@4!X4c3&^D1e|KtU!ax z6yT(2lH!~KOrVCqU{wzlkb%m89e@#_p;V`41=M9gnqU@$csF?{2Nc8<5=be6VFaPR zZ^#zpWd*$QoL~Wvl=2D%G9eri6|w-8$YUtt1SDi1^7>S60M+o=sW8vyRPZM^8ry(I zC<`TE~$d@2aCQ23x=<%`HPkPq)kE7U3!D9lrGL25+6eyCre70@Bz2pIs*3&;~0 zC^ac8)VKx6_5mZK69PZrgHu1qMgK>HP}pT4Dr_hjp)IOg!0(8b0S5u~ez^&is!X5` zg~|vdU|T;qz&b-B;GiNY4Vuaq!h98qBJX?{>-LvCP}(0ijXuB;#>_-=0hQ&N_V|?C z5tUGc*sr`w8Ih${O@G)CMY}-nBif~*9_1210&4yJi${1I1+8MDHid}d5Sb~p0CRj^ z;ANCWswS&yp=1HNHBBLz2LcZ$HG|-yS^;A8Leo$&1iolhYLEdStx>II8^Bxu(4Qba zik+%^AeeqK1!osjg$R_WFKLxgCGo0_UTF}lV#uOOLa6VD9H>6wBf&P%SDg=zpnw#O z4=PSpM6iuEsy_On%mIoO=n5hPA%z9~DN-QzS6?NoUu6er=?XU$qM|^es7DH4kVi$4 zg0zV809va4Mymxu^G>-Ya<8;jD5WT9q&6*0;TP1av{0>)fS?J7B9iUXYnAh)tAdUN z04l9g(Gp^t6wOjOMjonHz>Wx4fK8e~xllievOrsns8xg!Dv^Zwsun7wI6;icMZ_YJ zW*pU*2t)lua|v#KMIoZPs-~*YA#MWANE54Kp`40BP{hzE5(Mp_RV{(8E5b+8@xVLI zgj@a9TFI|asq%#A8sP?!tW0_jxPYB_`&nim-=}E(n{zZze??O`(I+mY`2chRJX*6N z4Parvwn7*av1)*D#AHW!3FQ=NC=C`kG=PVFA{YR&UxixL#Hy)$f(AtB*P5EDK7AOF z7NfK}(q@%heI=t;5ep+b*(g*+v4Fb(Jqkd3s8+5jme!{#_JL9{QF#?XOSvJ60T+Gj zS9qgnW+Y$+Pr*v6{DCN(CN)jp0gZ^6P@6@R$q^A~wGcKCvQ*^221hv&;SrG2ztKh- zSu|I)RmsFs@Bm7E6fx#nHIZVfTmx!-pq$Xwlb}Gf6k(nhcH1D%U^KD6*fsD_SA@%b z6-CXZ(vK+3I>JBDH;pgR-c+kC<6jGE{tr~UkH~N5U^g<8dlLJB0)v2UJPzgr7J`k2dutKJS z4WO>bR%ugCqIG>epduAj%Rv_4i1t@BO$7jBVm=`ou?rC+)2}V7?vCPN$chU|vI25_ zYOF!(mqZj*?b8_bn*fX`lj=5T5P)^jCxjtNDWW-wGZS&h`|~~8s%gR{V&|gL(-4SQ zCm>(7W&>HK>H#4k0zu&#ffTXS;0j07o5;!ug6wmMBDw}Fh?LSaOmz_Y40Z$>yygO` z0EnnsqmT$yfghrAM!`a{|0?l>4TQs*4nt?A$Q{I|c?v}J)tY40w}_yr`S65+D*s`K z6YUFtkUk@zF$=h)_S|p*rHJnNoJy~wFa(&Z)}>~Os3qZOBzg}iq-~NRl$ZZ7Tqe3X z!7YAmb?A+5E0@DdxPg;rxP4Sxn=m{H(u^J$aC3H}F%fp=iIF8E%yctWD`z&MNnG^= zDW#>9MU|X89;R7c=0aL>E;Pet4JMgRWmdT11SIn@mvhU=@D8mmu>xzb?h~v=xY!6E z9K4ZI2k``sMaV5>q_F83*4T80ftTkEEHlBx8Vt0aJ1CiDnUmvr6Mj<`WSf!W0sOc*4C3JjjaU zO-?H-x!Ae!Mz5QVOEODa;|$0yK@A25|2928p}k2M(Vo)f65O&R3nu&n9HePrfN6#& zynt%Fl$*f3&T>$-1+6i0E63Q%OsAa;5}x2#Bcr$MPD^D4A&=z%B@{1+MxZCpC>bd| z7Xy5Q)V)?tki^PlUjmAC8gCLfpWBqO+beey9E?_Ui;~XS$HZnPn2KXIi=0hhC7GWC5f>wEOTZ2;)3L41`R<<6doK3^2Eg4p|Ve2k?K`#mcN88%;6zK@Nz7#oXvCk##|g zEFSW`=H~DZlHie9mz#4T3y=pSohI@H$ZtbNIFi@NnQ^ZoYZF@P65WT< zxp}O|Q+PN-NKB5G^4u)-aRO_MkvO}P!9Q>U8}Grdx`d1rE+y6KN&%3BUo5qOC?-%9 zTJ1DCC8*m(J?AsoJT4){%@#vB0gaQGY!}Dj8j;gGffW*!QxpS?BxGmSiuTmaR`f zi4l!N(44GpHz&JIrgjNXb;a|R4FZ=du^iqef#Sg<&K81Cc#3yQ#<&E^EE?_jQKC); zj&VBlrg+idklD~d0VeTTtCK}@<9S=0RdBlv>mq4p^dl>d0txPGk&B1><@#D~rzD6r zWRkg)Rz`Btv2lVaUo?tVT8!avl|m$kN<2KY8O|o*X$DFUi`VB6+F60xLxURIP-wO! zSY<}<A2J zze*hFu>{Yka+8GWpsl%Gf}Btp^em&02#fuyu^Jpw@kC%jGJBya8iVy3| zK>tM)I!|ikjVv|YXOi9Z_*$UEN;_nMqbCz(ga#j4AqtWV7;_xD37Q)xvS>SzCfKIw zz$Ex{g1s|Xzz~8RpjHTw2f&A#0C5{9x`d;ka8}ytq)e1S5Znoz%Rvb?H)*DVfk$QV z)*m6#h6fuMs~wb&Lo)>?Rp!bj2ot8~j_JzF!bP$G#~HXxrU$IF%gM&L^#c7{E}!Zb z+_?$n^Q(=b5!M+n%ZZ_Z)@%#OF2d&&j?%g1;*5+Eb0RtcDw@E_aTe2B0mv3=1n3hu z0WSrmp?UpIK#xQDdWI380V6X(i88|)Is8B_2RvrOd+mCVwb3PQBr8x@vJhpCPl$0# zT!NQdY+xnce76Id0hj}@ImPjU+smaud&f5kq8>N~8)E@#t`rl#lm@fP3gLw!kvMc{ zQocz}kGH0$aC8Y_E@$GxAE_6&(}>Sj^_jyjJB_f_BWRx)ZH7k9p-D0etDL|_Y=q7d zM3M={&}h8D3ew>9bcKhsEkm50lQ?Ryk(F#57+c&`T^61qg2_JGm?+m5o675DP)Cl3 z-V*u_YO!c^!}>uv!*oW`NF)1+2qr~f*Sa~gQvwhimKb37?a&rPmUQMcm6QVABA1bC zlEbHn=>bw@_GqR6*3Rfj;3#i`l#;@F(t#a|l^!%DO@vjL7GMB0(&wRpxdhH-LOa1! z+GICxLRU7)nJqO5jU%M*20&|T0_7+9S`^F|=p$b}0f&TO{|E)(~qpOf-9 zJR!zt1G5RTrq_cI!4|^$RxFhcg1V5#D{}{BRw*O*o-7t^ zWhqi_v4GH9U}8YdF776oi7~Qn7PZP8VUon+_gE)7>N0_Og}czFEDsIula{wxVz-kc2NG#oBftJBa0u`F001;%Cp6N0{0mf+yFY}pYD$OnW zQs@9f%(;=lYswf$ocRfb{W7c%!(D<2t#=DPFYAGhDg1#5JOIt$o)iSA0Tv;0)U_G< zWFB-k35Nuu+f8~uDN|+v3BfHKrX23E|Fr1vjV)r<&rU8V&XG6DhS=10CeL80t;=z z9cz`sC!qHQs$DF;i`Z-fKi>kySgM7U(G*~gRfP46>`K`fpTc-Dpy#NU06iD9d$dWg zf=|Ykb1b+=R_bg4rqohP|ZQV%-UXX?#3uA`YOFIgldd<-$(E`OcV;V}!}m^G3|g&#F*7 z4&j9a))wb9#>?CafJ;Sih;bd4aYB3sJ0+q`OM#+;W#7{Coo2cxhn~pf zz%a}VFhdyf$RKfGNRm+yMLH17=LX1yls@6%a)cB@2i!(}(ZBPxUZ}UcC4B z-u>?T-h0$g)hF$zBt%SG(`u=} zr6`AbHiWbWc|vBr6z3L=-&BTpwNm7-1P}|kBtP*WNZ%qppgB3y;|Dp-VuNFWK2#SQYA0Ua0SpoSMJ!><9 zF4BCe!_V(~s89q6j>TN%T_MRRs+i#knSc3I#$>10Oo3>LdixmZ8$2)a;r|LA;2A1X=^* zpA8Y#Rh|QV$~Sp%SSn@027%^wgZNDX=KHM5Iauv>rL7fFmGiaf7|6>^c>IECP&ap= zwsg8uDIG~_v$ywUOkx5Y;oA^yK>B}!-EQV(NNfW4PT<`~)fRKE#`y{3r0Kf7WK_B9tE?ZXloAAdpv0UlQKo>Tv zrr$bfnp@#%N+JBMlXsp>Z#M|X%?XS6NwMmuD`~Z*+KIlx%-M!Y(JMD#o`K2uCRyYe zB#lCbh@ztilNze=C@7?e{4En_+YLjj?o_qHIG`RaK3{GZ{#RA4Jnc zh69je!z$l}5rC^hs>w`OgI{sVqk`&J&AZa8F*x8Z>Zb)pB7E?BJE{Q5xUo(QxdqpF zd(ii(+yOg1tx)xm4R;=s?HC^HxB)@{V%Uo?57lnf6oY}yHzq1 zMS3|Kg$Hi}2y-A8=5awpE4g3@4pW9>i>^nYWYaMXJ`IEnSSO~^WPnre_lxzUS$IsV zREr%5{hgTQ85Wx35}{qOky~bAw%tp2_*%8SZb<>6*0)~;J6PyA9%H536;#ZoR@~wRZX`SF8u`lP>Qi0v@DpIh9>hU zCH!(i%olc;U_CI+pV-}rff80&mI)17NKc> z7iFm~(tQ}68K3uE#Ype{2?1sS@=%#?7Rq|EE2$Q-6<|23vizo%!aXJkcpUl+osyn+ zf&~_X+MQ+K1$j$!-RGJraf4i(LB(-b5r~4$JdWeoy|!p*yybFAid_sH4`4-%%AF_= z1;@M#=zGzfUZ5Fk)Zlr4e8KRF%FxP7(J89xd&X^XSD_X5{bA|_u2@1WMt+LfA<8%k zo&YC-pupT9UkGO?w?@JRFoB6v8BLKn_9mTD88E@+Qgc30G5zZE0|~3tmzI)wQWX;p z15%0QC+@VsT?`c(GJCBCk*ImZHG?r=7Se-`qyon^CVpnBL4Y+kbh%lYqZv@;0C(UB z?16)Gia8<&*LH-RbOX3!74aX;8juSb;|FKU&w~z;ZqzqlL!F)mW1&sBNC7$Wn$|Bm zt{&qR=W)(5A?Z}}BT&b#cZ=m*Ppa6%1iw&)8*+IgRq+Kd$yYgA!bU0l>WE*<8pw0S9dWN*LcJz8h<*RLRvwIu=Xl=)S#Q(m)*G<_7z< z#*CC=X0Qr$%m*J1`xJ~|DP{>B1`n7B<)GdZmr76s5zKst8IxnU6f-}sVFn>6CKd~H zGaZr*lS~!SR>~}W!GQ6X8eSeZ(QoJ^BY4VFvi3&kQ3Enbc5;PUbG08=mx0Ek*00ept>w2>6ouSf- zYl7nriOq#LD5nS>4&`n)9mS%?XEMPHnSzmSw}oPc?3m;yDhAukz{E-}7APYn3iEkL z0dbjr$cc8uKx8X_p44X`tTVX^0U_EHix$ zxEod5Y8s4agu7K$almh-(}~ik$xnPffN+Mx$iA$)!CKsme-n@;0uRQ|{E?(Qs<)};Hvw&|(QfjnobWMe!Me`D zgrOY8aoFFRDOF9u2pp`=p1SkEv&UAQ{YkJ)+rf;xoJr9KVrg!t)!o*Dlz;tPP^GL8 ztj9cAa9x-}jo^MaO6XiLNivlR&JYl&>@2@(Cjq+=cmF?(w7LD$_yvN0GR(hbfOykkr_i_f z8RA9gPu~o7gQ4+eGU_C+5g5lM7EGW9`8P0l6($06;_-dhi+su{m~M_W(TU7vU>_4e z#U&fV(PO#8Q66Zrpax%+9M}TT<+1C0z>%^qm8;~3s4nHOt`VF=;RXxAJOdC2ppGZD zpRrP(!Y;?(hJ=9;7Lzd;r??0ljd7^}3h8psUhreE0o7nXgi63*2x+r^i;F(_0o`^?q)M)XXp1vjvVdSK6}&VzDbmG1?~Z*B+o3;orGfUHCKfNVKXNNCsfmzN0@0(p#mIirEMxF0)a8x5XwfIqD}mWNHThcdtQW*Ar|+8 zB3~*ArGnw)m=`5G2Fokv%QGs+IfBy!<-IVQk`lnV&pZn-i|O<{@H8Zq;Ckbfk%RZT z?(-@@6}tHcbc#z87Z6RA*x;|0t0;&zLtCCPK?+!O>daUj#o6F=Ud0qE#feh{24IPT zlnnW!U%ii~W=vkW(VRbj%JTBSs*h`xO18tK>wt*r68JCa?Yyux)%6;T|5PTCBld0fW#js}g0+Y)T5nBFV$_g9ZnqaawZ~ZY*sA zpW)k+$?^s07)oCzQ?r02VhP~JPo@2Krd%f1hxDW&vTZjyQ8j7Tb(u)}?8z}F_%cO$ zX#HX6JuoY7c1R@riI6S?AeH|ly+}Fr3z>?MYDpE&Yv>`mx z!B@5RmU(=&R`n_UXeXdW5VmP=sW4Ql_GL=7IT&?FVXkJTv4q19(JI0i%q>JgA*#AR zZ9C47qQDBXYqo+W-wswakW}mO1TCUIljwr_;E^3L_S}b zWjIYsOqjjGx5-)5pTdCcl*drrku^9-%U@HiqgVC`OU?Jj62B1=AMi?(^`hnZ{fPV^eee>1v#?0Jz(EFs#y1Y> z2XThzicZpliX$%qtud|50G>f`5SFSD$AXujwe$yXqr1S<53RP?Ny0+PxW7aTtRbxj zn%nr$l!JI257JB_;fFTa@5XoI6s^tV6}? zPMr<=o6wHKo&7`*QC0YyA#ny?hFXWoR_NQ{;xK^Af>`c%P^Z3u7%5_avGoDn2_C&P z&`rPU*gC0bw<`|v7-(XF7uv9PnBxmsE!rDRzT)v!Rzu)}9OI0FCW|Q%x%kAW zFR|u#v09834$(!RJf{rvQD2F|T&d}Z%@Bz$>UvB_vnuCSg=lmUZ*vSAwPapSA$(F| z2$p57XjHZ&QOt{A*ov5HB7CdJYOEeJU9neGs*2XBaWO0yNw8QaJdTCE)pD4U+{Cm< zEYG3eTu`;EkwaSECSs2=W)YiU?`% zU&K}6X|ZYyDJ&#LtN3#z&Tc}Sh}zqhUDPThTe&FH6fYT^>@%gfT|`4w9l4?^){ra| zR1v8m`b0(~h><5&GhqZB03qX5c|F+!OPegHvL#DOiz375uQCF|A%&XA7*SZY4uIaK zr=gZGvc(rACTZB{SVf`%+ma2H2YaoNSr)6P4q-G&Gow+iHmr0u#n+lLC&P^)#kwG| zOhVxF1J`wQDAga2E@uv1MP&B+I|P<55~z9FM#e#e&vnfFz2|c|j%soILA=BB5+ZAO z7GPbU5ZQ#tKo8eMcJJL*HU`*24&bn`;BqmJ%z-gr;yWw?%OT_>Wh+*RS+-V2I&VM2 zR2<1*R8PciE$^k@o5|~%B*vJDE4(5Dg6U>>i3_fXCh8=kB1%7-ZUxTakUb$*k`VSWeUwQR#wJgqV787*&iDx~^0l87V**Cay?aGKpRl4I!bX zWP?QAZs>@DuJf)7V~VOF%3n%pU=MPNH`8n^ngkLTML`h}tdV-nmc zh628$Lr%ES725>N8qS<<8e<0Esctm#nb}xQ7X`Kp{xq_t`yf|akMc3UPq49a93!@D z>b8&u+=*sMPV=?6vBZseAd+Ssq-~}J#p@iktDq1oA(c~c$%GS+rfo4Y_5mYx7App7 z5n6fcR8#3fI#;;mK>KiYE}CWy zO!H`>yXLg$3B|LEB37x5E|_ffI6!rd6Ed=+Xq?VQ86)j#p2TBp3FcTK z#w4)Gn91jfYI8EH3(y%1SzYiVk-IiI55;D!O6cE>DSeD zLV3C+sCsZ;a3VARViw%O7n6dh107r3E0VO=5m{tuC^IlgXbk8-Xq6duiz`NhZ7{+I zXM-@w8(hl5@Q7)+Krr2cOxQhNaOcfzX%m~Ic+!-_sG|AU1uTLrz58)T49LSrF4O{| z^xLuf*)+NbGh1T^*b#OXdkVXYJ&(PRy^_6=y$PAS?m~Roz3fAXE_;D}gMEwL%O&53 zNs!&9nR=wcxeN#zGRDT43Zx6fB~H3L6>{P}S>;3Oh;=-G4O_8$BRztddY|B>(g>nw z@&h+ADy7P}nF=5KWEU_<9E#@(baiRK|t{VTV+lEW3R)Vg~}NOn2o9%Rx;L z9|~C;!k31SqveM}3x}aJ#xcDcLYvC4ir6>M7d~8~at<57p&nGASL!`|<*C>LVX^{# zZ+{t=@UF6m47{OyZA7iUM^5h-+mOk~eFffxs}QM>aa81^{s^gWoTBvxz=A9us6Zm) zfC_m$;}?Om!v4f#=tkhDdQUGpAMgbI1fbIBF*FB2pds1uH=gwT5DEes)d#|N54a(? zp$Nf2k+ciZG&HI44G>ZE0dK-8HgYb9;0bSZ8z^o7eb* za`9Ec=81c-qvo~Aq6Qxan~!tmG?|aG?CG{`v%pV+#)^y$WQJvYPhce(iH0oIVX^8# zOowGOHrXsDJsrX&w=AJ^oeXF4L}Ia0#z~B)L+mpNP4lBtt|$u%Hh2;^cpXq%89W8d zT=WDPP(VmvrV6mk>M#;RKg5C-YYAA+Wkea8rx0aTxNk(cET_6);t1V`$ytH7Rm?+W zMaU9JV60KKNB#6v5lXPka1aD=;1XCY3n)Aw0nZ6qoFu6sLK3uG3aY2dPz=R5c{Ky$ zoZ_&^MWk|q2ced!uvooK@w!|PSPQr`XY&kkRBHioAgR0*BX=scsAJzIk%45yAfV9- zMguM{vcttPitR%9h%F40j{Sj`uz znW$q69RBGXk6cbgfGVvS$TlwI4Lpa8ID!Y5%A|QIfej|$F94I7EM~+$z($W#+v&oV z8x663leOjMJsFA{@ySgkB3eFqnX}r?5;hVGf$CuT+$* z&AJA!XIiQ8vI_4NQI-19Yj9v`U(9Opp5X-HV^}N77vQz9o&0vs3mE!iVIXamtTJ!& zr6YKbVpFZo5Lyo&9)aj7!N!PkTrmnf#JjDfmgEw*4P7Biz-NizQGfw)CYSv8Jf7u*up?%n-Q&%ZiIa+r&M==3ompKvfwn znv#?HHeF2erjA#zk=9JckUlcAE%aE98RrMAc?EmE~01m4J{_zBp=U z)M(2v7h{E{aI{6_7)nb(&j>cy5~8#p{X?o5Ctwp4AwntU?L+p9MjqQ;b+r;$SKxJ_eihz@rdRAQ$8eyysOx z)NEMjjq*a#h^D5tCdX7aU2FkA=EW#fkXTaT2N|sWK$j8)EY2jvgW-jegTEXKlPt^* z6scBIuw;T1We5cZW_C1NS_m#f^9u7^GbRSZ#d27D5HwMjX7J;(#q9leP5Ugvh;XtW z#iO6Y?QopL1YmBk7;9n+C`ojwebCN>Z!;veOcWug$j$QGti=7c8LLc^U6u*@)ziWF z7=t94$iRCr^%8P8c*SvK2Que=5xH}}hU~cylSj!DOgq!Z3?hT>hnZc>dC2>J6Y@O# z2s_+8!~B7Hk$IJQgLxa-{{@!zSc=Ud%l{U3EBkBqS+1KK;-+)UxgE&au#5XP_e1VM z?h)?M_n~hJpb@P>v9};jZtnuw?d^jv6`D7tapVJG?n6x!BJ6{%urM~$?bLz8C=vl) zqo@RMpnDQe?JJA|RR9r+*XWKi6xRTlgt(_v$NgoXL6Jgln4|VRLy-%`FR<&;q+M7g zefKd6OK>yAjtxs5g@P1n0|C+3Q&(a60@_kP zOf*At`r-oc6j~ehgNv7;p9kupqTwJ@Kv@0$dW8b6feQZj0jRw24>43W0Ng1Cq_4Bf zz*eXVtRhv%0TbT23p9dozhF}0hhU)sXU4VNc zRjGUjU=nx0R|F$cqGsTJXd(k)CjoH#edy|tmMUdfn`vg%u*LO$m~v@#1O)gx;c1+q zkQ)bL1Mt$GLYDw(67)U7?`wElsSe{Hu)Ylgb*~?u#JFR#6QEw&q5%*Zy&C|V){`n9 zs11Ip1|zsI93x1Vk`=0oHao}>6&~R&_)Ow_yc9DgM*68GG9;vTu{g!WbpU2M@{|a1 zBc;~xgT4t%K}i@3jQP9M4pvO`Vi_ftdfr3c4Jr-wf_~WeQCDau z=p#DCpsj=?jT-OMQt3ES&2h5&_=~m#6Pr>19_q%6&?O)wXa%AAC_wce0mDBOIwY!*BkbnDPFn@`xxtNPM9}Kbr~L9 z692&!8{a&WNjUH^0pH|A$nLZ;jO}|Fpll|}sd6pJZ4G7xH{~^lOLQaYQac5sGSrYx zrB36)r!$^e@6aEu^L^#lswEzW8Z3@Jq< z#uQ=avKU_RWjj4=#;H3u<8`gb#&SZ`B3OQmLHc8(1IZ9!A$C+$*@7X}B8*|HOdPA~ z8Wq_{j>w9*KWef%!^x#23lz-71jdLV4L^gWEMzo|;u>_IteS$EiQ{Z0K~9aE#e=P; zt_|@HlE3-Zx7R_i1$W|${T{OE$`wAz=u)qO@Dzw+3Fd8}SQp+z@q8yy8Dw+?T&BiN zU2xbjC=hSJ*aaVbR@lfCNGl_xEhM>dL>@>4=2-H85>xlCMG=m~JSOEOzQXWE5~3UG z03fhvi+q9TIdmxu+Jb07dt(u##ptjCs&-0s`C9X~mB68~2-!F5{ddbc^f># zNboxj$&HacOHFG~24EBB>HyxH%u7DJ95fip9oR3S!+9smatoYO1P`V?-~lo_mls_N zfqn~tKbYIP+ob%IV3{mFr)dbAA;H&L9gBMc=#1~Stj{89jFo=~2rn=)D{zOzqKh(U zyWSkbz3Hfn!3BMBP*1T7u8Mj95F!Vx2Cx{z0>8+#Ce~Mdk!w*$6^U5^_a@Oz7claS zCmTi*&W*ChCe%bM^QvzUxzK{waCE$)r9l=+ci}V0ut`CNA2hVD7@Lh6qUJz_!ao(M zm*u6V1Kmznu*?8grXutsGs+4lB0sL+P22)It6~Dvaj-e!2@e^Cp;WOhv4M01gNZ>0 zg5CtBTSP<`N8%(eCkH^xPzd%uX@&I^o_jE{YT_>lXG2#ugWrHyNh>z0pxx-r!erwZ`jntqO}!Ep#p!vL zF5jA%;$kd?`N35{u}Uy67R|6vVNYt2$q50xGv8-hM+>6%u#mwFbA+}Ln8abvZW0-W zG-GEIP9hmt92jW0Cac!=E+Ctj@;EPhE_}TObTgoO7R`sZwhCYL7-#3H&L{Q34(pUs zE=Vcb4c@`noFwrrFr>>(90TwRs|Bn2(o~G2j({+$=rKYb!C_d}X!q374lkjRb`>KQ zP7WysCq8{X^29;`gqs=PBtp-JiY}-%!O+cV(WufZ!!jZPjY37#5Fnw!zsP3VSjlC* zgyW`E06$D6Mb#y1{#Zuq)ikk=%wa9r#O8!72_`?v2D>Mo_F1BXXgyXx_4T(go-jDW zX2LM10&cs8Bs$PAV-7Mi3oo?mV4S2{%X#+?cN_~ReTY{D07?>4G zny?W1S3&52zQg9>@^K&Bp+)AUxCV!dEHiO2(@ZQDQAL^pcK~cGf&_Tj%}YnHD4lc~ zv<5_*X1Q9N%TgV;6RH>|1P5kwQa)itnP)*-G<__~`vB%qIB|f%U>6Sz2G;D*a)pcX z2ms?fV)J}~iPl)c%e>M-IPDcE2<#5908kLak}^kN12S2~%0O*_hKXXji6ua#R~%?D z1|~t8g)7DVJai!>Z%a^d0bM+{9&7p>*Nw5AxP4Zd&rT!D(Q8lfM@!fwXBpp_Yl;Pb zWTEXi{Jlv0{8b1H28AnUfcWn%u+#{{MzPd|BpkAgcd>$qK8`|7l%VT*97sh=rwSIs zCVpNtC8Yox2^YMa>rmrPxrF7+G)TZ93HWXaN5Ra54OB{PTr5>(S?n0cD2Wo4h_c1T z@&*=fn&3mH&`{+JtV`9IZEd38#K>)$gPhB}Z>gB7toB?*#L~%4FdS$$L2rl>rlGEY zT^ATzGjtVWlM@_*T)^OmLJt>%%>i4zd*HoFoV^drea(o@fdK}+%0NDGE~wB#%doNp zy9PQO?OcuS&=KEhAy$nu*m1^zR*OgAalwjkGlZguIRhOM)6+(fiIRvBMopTUgy)4j zl&BaRu%Ur+Y(bLXu7;eq%iuq;EcBnC`EPUK{&zL(hB+3Q9a#`rhW*|*Mh-(>Ol&;) zcb*eUCI;0rP7IlcgY);i$1AX1Nu2wT8~0#5Pt z>47@@S8y|ZzF-l02M(oW?_a16F8apnJC>Y9Zd8N4$6vZyxOvTaBYihKQ5!jT?d{A} z!m_(>XTK0E5>{V&JmL0id;J@SpS6Va-FEjff&F4I`}Vt+eH|xuyuSD3OOHpe75S1t zUPf^Ivb&l7+i&O_IX8IZ)3>9*;F{G!un1t`c(M&IJNz5(XNV+!>(Jf*I& zShr9=Xd@=AQABt?(1M#@430i_19_FKCEU*+Ibw9m-1YZ<@28m+qes6?a?G0Gra*t~ zr?)?a%WqtA;VTz??Mom3-mY`rdb+ZbT-kVEL@e{aj6|`1_nw}liv;M2NTEo3ppg-` zmPh-`6MKSdg3AMVIFPMx{p_KW){F*~;O?*NK0IsOKhQIFB$@U6bIcLJH4}Tt1UZIm zW%zT>dirxulLh3NM{a)j*pq^VFHO%?Uw<`hYg%}MzXfeg|HE;h4k2dft|UAWy!oe3 zel_@9;F0IZxm5HFVEceug4wx^UpmJWO3U! zUV7E2p8uzi?p}qz$PYlX?_cvYp_?HCw`0+6uOUr+fKI+DV9PGVO$x%iw0WP>6+xbeEG>4KcWMc33?ip7s92;MMQ@WC~G9P{G$m7z9 zpKSTal@~E9&^rwJ<}lp3Ct&uR#dd9b{=2{Y-Ggth#X?HriVH5?z2m^((PxjJzhtsb z@5sVW`A?xngOhcl+>@FrXv>TH=2=4#4mEt*B`h5p&!zNOp;RIKbmGrQ!G8AMWY2It zy5**wXYj*MAF*`vs%)nzjnB*5Qu<5F?(W~T<@WP~Sa9204UE)aPD$^b)^oz4%TL>V#iHi(cZ*J^z4MsA22Ve7&%H-I{8n&lpq&$3MP5VY z16IMvaSnDU79^sWnh^^XNCLhT{`nuf?E#jx z6n(=d56`6XYdkHtL@6oGvV7HE#^bMrR~J$pYd*D5F6{kATQZkOr4!jiJ9#bBT`!3X zMRAGfjf^s?Z_l^g5yhTsTXU@RI=*+~(cbX*EarGrNWy$siweCOSP#vtB;y_TsnP*k zx*a_T=2|{!&!pnMK#ctCz2Z$PG~_8M>x)e3+DdL|c}aApG!i{v9+AaddvlAkCD~#+ z*^FbgP5dUC&UJM)HQNLZuJRRXp`#6BNBL@jKbXG}`Ry;FV z!ZTKlZ=AnH)1UhuIr1$MnH~%Uw{QNzH@C-2mGkAn<~)`khWnrvTXxz*u3mTMye_vt zX%5JPQ&MwXV|BODT4=xSyit>oyilwnk5PXs>BlouF*Erqv_%+ccvBIQ9y_`v;+q{Fe zxh59%7Y+3|HeXQ&4S}ClJZAY^#``^X3JCep8_4;41^h#3M{8Gf9ocC|RmCrv%xV_|<2Uq@JOK|hE&;9G8WI@jzGemyp`Pa1P z&=a{MV*_o8sGo^hNn>tY9c5~BXTWBWBw0Ian}q?bsce*3Dc&-#YneB;c?n-~M6uel zs{c?dRjOqr>9-%!$?~Z~yR29*ys`Xjmaw&!b_2Og7MJ>3I5? z;0wWBPe138MXQg=Plp1GEqAdnVtR_-l1s@~lhe|E8md`g?H_J_1 zYps!p2-)#_afJUF9x_6oxM3*f81Bk)XV= zZ<75r*d9GaXPO09mj-_f=Uq5|TnFx;A<)7&hre`I(Lccg>98~op?}k7a1{C>G)fG= z!vVzY;f)lvpbq$39GUoQ@X=4-@@DX_usdxhJD5m!V1TjT9u!}El`Mx;cr{otmTvDz zO#itjJ8LhS+jGEmOVlzF2esNQ&5PssbJ_J-({EdK*^x+^^o!dLEM+f>$JFAisBWgP z^NWfIt|l3=GuMw57ten#RaEzWvLmx%u#jwHL_2NGx19NoK58WnO|a9Z`qCmPK8q_2 z^{vu|yPNu!#gAUc929(X;`KR)BJH%a`D*9H$7MMl=bUnLcXvMX<+vGZ@4_6-V=u>R#4qxDupfvFOlU(V%D~&J z0?)3g*cE&(cDddLZRoVf#gQ+79)1z|_sFj!FGOCA`~~}4GXzFVViJ#}A`uzliBurm zWu{zd_Mzi66CBxWS+r|}uUC+NKxAS2ZLY)Q8_s&zmBXzH5jgkmCAI|9ILIKBqWy5e z!dQ#cR1R{$UC4$hf=yGG6x$JCA$j5I0If(fD#D^7&Hc@=_>@?judo&D3d>jE zwaHfq8ihl239@T^CisD$Bpbi-7-lgc+kz9LF8SPH!5CJBADTF3Q=xeIk4mM4!+t(! z!T3GC=gnealg*vR2fdnbgQzAqCXtDFwgQk5+TDI+6 zM;mNs9MXHY2-RwDPVcZ~&XcT^@VKo-yQ6Sul$s^{Vc11w%;a2;Pw+@!4%Z=V;zc(a zoT%`+8N8Ft{;VzzFj2S=Cvr|8X-FW&a~Il|7Yh>?1})@qmb{a25~gJxdAYr*5PT!( z<;i!2S;2aRToipcc*lG!J09GilM$bLn%10*Tu7TqE&?P+>5si}MX|7%xs3J;`ED?W zcGliG*nulSeoXt4-*c9|xlnvTDM^USjYf$?J6d`BZIlcC35zrAx3R@D|UzYy4|HR!esdTM9$Gm|@s0+z%PA z{Syec^L;1bA=<;!$(wY9&9`5p?Qwh3X;=0g^1DLu3VY9qw5b}o79CK63WeSv61s;x zq>=8;_7%lTA49T`?6=XE8!rHW>uY zCHQB{lc=aZz_ZQ5?oIhbe`kwrq=xsl*Nv!h?2xB9g;Dy@e+qurA|CH##C07OK1{cFRW_4~}x`b4ZC2iavqSuz{#===~=fS$je?{+8bG_?=dq!G5 z^W}-Vx%diIzF_VpYp<*k~i-uPX4Xv-2o0c3z5~ClUzg+!%a8XNn&zZ|ttX#1Q zlJQiK;|UWVC1(YvFgr+l@J6tZ#DZ6g#TK`JW`Fn`f^|f21N1W$S(7|w|H>cbK4B;0HaZ4&V?ZW{qf(}ex1kIz;4WGo zm4JQ$3tn^x(BV8gAlel%ygC4%P@3ERXDz`~PPb0VYRs^6?UzkV^*d#!`?5R9<~#f@ z$*N79-mct~8P&Yrmb)@jEo98Fl$Ep2J(gXjiaNf?7f-}kBhe$uEo&1$wt$XQpKARb>^?sI2|K2k0Ltabpn_kBz zWl1fN)%Il*Q~Y+R*SqvCviV=)9b)iXuT8l*Kdf~7EqCUJVtbpjmNM3JNbvck-1cJ@ z&hT5!G0dV(#%(Q?WPSLA>BnUj=2nlMI?zOp2tM(L;JPQDB!_(Ev%w3u{!8=pVoSbo z0>gZJH=PSC^SyUwVPA<)!ID>sbVnlL4yhFInIS}QO%IFSCRLjRWP}P;vpUwTL!>fb z)(|E)^35~Pym!ZkmM=eH$2C(%T3e@1Ie5m5gWKnHchBj%v~&9zx7>2Z#cSE!%a1={ z`QFpko;|OVeW?}q?KL~*PhYiadiU5^cW;RqpSZh(`jE)&kqCD_|6@o_YFWZ&W0ONZ zfPu`x^X&ZKsRthjp1QH=^l2jpvYr2vA@qysCB>TWUU#VWSd*}DRzw?|6t6!mb zc}4II@iwFe`&8s+l*Xg_IRe`hetn9bCVvFDO5;dm={Fo;!*9DD{y=Xj6?y8dTo%Kh zN;5s^BF*79@6o?G3bEJ*(yD~N12#Q^yL0%>3XNa-VtTgmJJ1|fgl|-*k2ckHBDLO# zcw6wNjPY3T4i+cB`$xs9ocvQ&g40*~wPLiuCe|r&M_TW|cS^sik4fs1`1omgA$aTS zV$ld*{)1Nz-g&WDeS@UZ9t>Em{I_6<_fCD-(sRt<&4Pjw78yxjTVr#@m~l-XjNjP5 z@mHq^g{bkH&qb5)pLCyzmx-~boINu5(km|`>~PUbFO$XOw;q%C)sG^*tQ6z_bP}Hx z-@a9DGT(es$p){zm2%(OQ?>scUZKA5)j-Xi{iLKB7CUrp%+0V4^v`5;g~Ozi(JO0W zt0MercLA2`TVq+oZHO;RWn#Y2U3hb%*MBOQFf3R7);pS-k&gR`iS@{#YY}b8`m6M~ zt)^cgi-NmeehGWDEdsr8@cH=$;`f-ywXjfhkU1egq3po(DJZIhTNcrA|N9}fLJI=M zadLzwf8IC37~22L2scJHMBwikU{Gx6k%C1b*sLix!fXOzHK0_eSb;*I8;7;n$Mr&O z7iZ{=P?xFdO#j0Fg4_6^1}8XrK(TAk5{jnf&^Lsx4EO`gv)r_grl@9z=keXp&v0LZ zJJwk$=jf%$f*aMu^HSss%`4{2P4rwjP0hA4Cp;nL$v>jNX6dO(@@r*-KfRCq$|aB= zmQ?;@@i zq+oWnPveEua1WVLU(t)W)6DQfHOjs8Ydv@ea;3xnnYqMbt3o=?VDyHlgIV&o_+I-a*_|4XcS_ghL~$q zKq4BmF|+J_3OpX)KeOm2YPgrqtygE?b>vSxwf)BS_`&h*5??>5V@sW(S)P*t{Eb80XJjxBf^5&@Ky2r9CNO@wzx4ipl*pvuIPD1q`D)qtOrkG z?Bh(cdlX$nl=_8nwog#34VKk3R9(4y!)0o@d-;x}ZLQg`?eN8eGgj5(mv#5gNgi98 zG2GvjE3cdqjTY5e7tW{+vK@14AL<-5yLErl&`Dc!-8&ol^x1L5jC<>EnNJ z)tSBD>0SSY8IS3%Yt&C~8GNS6JFWG@WZj-S)}4Ri9mlL)o$|H8z8kZcKAhZQDzbtE zJ}E#P)|u{^$QYd;#P-Lc zgMEeDumtXSx~^G9Le~x<-HI69YzoVa)@5ow->r45CUXZ_xmIdQO&#pW=inA`fNK>7 z%wx?lws}4?^s!S9td!Ifm)8fm!D+MWX=kL#JIrvK5ZBgZwJd`dvN^~l)aZ(G%QQbe zrKfM@5R>h5Dt&_sU%qhG+`~o>+;Xny*k&mz$=P(#^LjdWe8{rKJ37k3>{(=x`O>j> z>^Ohj*Ojr^(}N$tM`~=OtFy>d+VX|v)5!w1uN_8v1fB=qZpcy@E-uE@QSA4VP_ zvtUa({{NwKibC?n%&ENl7rd({&+Wgu|J?rj5K~6yRA@c;Taoww&&U1qaiS0IQ>@xH z@`cG?0^gMIMDX4BpV@Z{|LFhcCvlMO=p0omgX;$;e_x;cC5OE4#J(F?_J3&JW2K$W zdwyMHN@UKY-QnoS&d6Dji(vW7|FfANN{)v7_(xK2{~X*u^Y+ii{Z~Ku-2P|(yJqb_ z2CVPOQK11xDQ9U&V*LKC+&uQae<(LSy?680lpkBZdg(~Z%H0QD3R$<}#D=V!xO#F1 z?VC6sFt`5W*(Q8ya<;7=P9~2lHbmx%sZ?anJ^x*iIb`%`?-7}WR6}HHEJWrh_qMjq zphEMY8)xqmnj=pm&3)_C(RF)04QZAHv1%!@T(FVUyCEkfiOR{j?~{`&yM~&*+Uv@) z6>CTSMyk;XF{YNo2@(EcLWI9`LVWNE%#iSgcV|c;mY|Z+Y~3drHT`cSW4~SQf3IY; zoqduKkuuhMWn-~4NLJ^WG3;UA5Qi(KQE}Kd1WZZi#hsJ$VjFe={Z8ZsIK<7u&Yqt_ z93gBH)cn%`ZWLuv0-=HffAseOW&X2yK^2@(_CWOspTT-0g=sKyG!(7yn<|W6X!QF} z-fRCC$_+zI{|_qnztRu?ui_KG%f?#NbXLl{nJJ^LVwKfwTB_>Vgp2;DOCZQ`O#Qz2T2JB32hcdSIBsX3Y}SgAZ#1mL5~iSd7OJ-GLu z+(4Xva>M_I68>2u*qM{q<-eUXLs6l&HRQ$uUYQa3YUJCIC--w=*h)zWyC^o;@PCOP z|HlTf|7+U7Kfx6hvBD0(XZfGPi}4K~mmgXh{HQ{f&z(A4eZPACK`>*VO8wu14<@)7 zo95p4;~C@s9418LB$#<{@Hyt|t53Ek73=>HFzi!<|8FI!-~sCgtAnGSTFSok_fj9U z#lA~hTR~TQ_EQ$dhuTpfj6-7&q%`b42;iIiM_1dBpJD%ra6tbHaNvK4{Qf!JQCKUA zo9CY;%)cP9itx>Owcc!Y=3-qvn?$%%Nm*w3nZ%r@nuXgQKw$hIbj4^y0^l+=|>j4_yo9q4~Ax&9+;N=-Ep zf!q?gR9MBG5{bdLy$hP#{KzU$E5;MXbyze*!+YpH@j=Iw@06(xgjzO3UyFZuz_X`+ zWpVK0{HB_H{Dv8Sp0VLfvh%ci7U4{#yK!dyS;2Qt56?8$tm6)v@!E{_yS8_C;@)h2 z%I=fL7m+JE=us{^vU}(Fg5cNP?YIX==jlOaFGaqM1Q}&A6CQ}+ z+IdLeh&~LLxL{NbSJ#Bl&&YOYLK>W*6C3x1C+WJwzS|q?F!1-lxyfFl(?49SK)@nh zAb|_WyJzT93tbbz2gOoDaxEVg5k^nKrW@L&LX$AP5j`D3{pPShoDoDkGD4_}ODQY> zCS0tVg!~5IRM)7$VGhNFWz&_F&^C;EH`3Bfz8qDBCmq!)XpN{!flB&bvlw1L>!@Nu z-$47KaRa?Xt4EuLt2m-pCRLdI7vZY=?%76TCZF)%y&unr&n)imY-${zaMTLJ^J_yde2NENJ#LuDopTeM#R> zVs}3)In@{{w@lyq>1<{9wKL3OS9e>dY+3Tqh`lJWo=mN2JzAmE+MCTTZ5{0GYU)}! z^4v)9+;so7k!MEko~BhwrM93&8Ec#V%Jf$^ELmD=>iGWj*QWQh8;e(MoYh+!o^#Go z-By0&fUf?f+2uQybP1)NL#K3gP2HLzrimVo}-st-{emn8lHO2 zhZkj+tQtMgAKlR`ZCJf}Lt8p^(5lr3-7cicXWh_#$kOq6M|ExQ`KL5bXE0~Q$g1Ga z;w}7v@IC8=m&?Z@pNxDj@<2n@f(kj2qiCq{*{4cVTBOF9{p1`@7wX#IAl=E?HA$9K zR5wVqp^4M{VboQ-;SrBj%EmvOY1|o3AiM#=`S1OQSHeO?zyIbfcqXh)qf(RK;d5c0 z0Xj>>Th>qg(AI6iUv>t;14k~~T-}su%g0Hy_3As1UcU8={MJ?OI)AO-nTrd@Odp+i zC0;0qDtW!9zOK-+=-6e;`p-XWAXaEuF?;sfc?YeUx#64-oqd0b#Lx0q^qm_VS93^o zs62nF)7`dWhBuTsH8VciUS4>x>BM7vy|;JPl9BA`*|B=7yUy)aX5~f?nYh#_<`Bqd zsZm>=^U=c&d+@E9=YEb6u0QERh;Zrf+InX%D&&Ot;eBTd58&K5WtQwnBIRP5xg`@D7;&O>#pmwmRo4$>cSzmd$(xA%I%$4oA;a zXC$*l3%Pzq;fY~*#K zAfZYHkweFklgZiSLUJql3b~IwL>?ngl0TAH7#4|Dl1!fIV1}8M%puHf=A+CF$h-S} z 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ĵ(lG%B)l3c=-FB-8SoqF>BZzNyc%8iUBbR7(`|xq6$LX134?%RX-R^TKOlP@WcHhZy zc9+HLu*1J~fO6tT|FA)?_-t`x(>p9NUZpkKq6&vW0x^=)>MFGwg{oGghKGz<6#{Dw z2b9GDi(aGG3AGv4uZdO*Myd#a~n;zu!G^mssc!BZ54QhJ7hEJG-8<#APOon3Zqz%R$7&X zHoeGIgI|(VY0`;`hy|DtMNb2IsJGigk9*v%VW-!#$l>y#C+u!}w$A17ju*{tp9Q&G z9#6Z+sW4NUfmlW^bpg_P+!Jt)Tno)aYecJ)S6D{w1}nQ2)fs9fy%LaZ6$&Y0HXB4m z$XW(sNG8o0l*y1@MaS%Vty-+&dC?k2DNyn8wlL>3*sG|Z6pd@WR5}1r*p*hJo2@h& zR6@k&)p4jM!||#@YlKorE@K|gXw6k3uh&=d7QJK%dzC4ZUawUZDC_JBPOt^kDy7z( z4`7UHTT~6`1N8#rXSIYxmEL3vQZ|#<5oAPND2g7k+1#sLE_ZgJ(=A%4DK4PzPQTMT z1S1D`IRaL+&JFk|c)A-l2SCMb!)M!Vq7}73BUQV7c6`F>wp&sTpB?FdV9xTpeS;1M z2!AxJ*{y`<}!%o(;8h?3uq<~6VG?wa>n?|i{07!znczTi3(>S?R0 zzV7^0Vnkr*>=T!H>zb-5}S3fBDJFxcivrzq$!X3mVS$Zl|^)&^f#wE672sM{%V^Y**51NaKGggVz$uru)dB6=78 z?ZeL6jpZeeo^$xv#aBL_oqz1&D}IaWQT@YG=7OrkV;kZ2a@&@3pRrZou}`o@36>}< zcA;H!4m!}DIS3Teus+hLK3KhwHU`JR(Z@MW%q?XBA3jYwBE@~SaoaKcxA?Xl55I)p z_adu7qxG%dcoB6AT7s|4Zi%kfZqeTO&nnRR$9KR3k9_;}UAKSv&26`Riw|ws-tJ3r z{nU;3@4fuNWh+tOr6uiDzDHy1G?v%xoxk{T{5$-}<2@nGk*lS$^Hb%IZp^-V*SFu@ zaoacFT!UVlqBhr%cZ0UYH}IFUpF(U|gv4$6z~V2jr{M*>k{LpPxPX@im5Yyrn8`Xa zig>6yE}+F*1gK~wlz+UnfNI%jG>U@}g~epXUm zn!(3PEv-?#wTXJxXR64?#na)f~uF z&=TO|C?m$n?@E*cq?jBy)kLHvM_Z1xkgOseYa&@oCug z+%jY985^X$)lvc-THe*UZcRte3PvlP2`FnD{Id!)RkPySEKVkqpJ+UD9GapefIs5* zSM0xL*)l*Q2`09S8t01LlWa$=Xlik~2tO=sNJy(c?OL_Evt!K)LQ9}NIa$bk2yyUg z&~1{4SMXp!83gga+=m0W0LSo~bFzOKpjLU&8(Rm^aeN3JquMFwK=u-J&j^H2k!$Qc zc_Y1(?SmXV<5&`4iRhi=M95M9#&l90-9ze8PD1cG4Hlco6Y!$1CXF$S*X=NGfb;aUU@%nN|7jZwj9jz(H>mf$; zYds-r{(1bMt4zc5bEP zbfuK1vkJ=rC9ihoGL(>fjKa<<<=m18ux?m4{?=kG^3>SvUIpNAs2GR98X{V!qgK#p zJPEs~;0>0zs)o^O6_m*N)H2ASm}cLjz55{Fm`sqspn~nNqF8D@=NPC_Z_7 z_TC%jL?%kwg4;R%fHptryT0q9g{YBgHDwud+FX#}R4s^B20NY;bVh(%!lAJjgV)Pi zT+e}X3(PTKPix@Dfp-DPymB#QUO6-xN%km=HIfbxhybQN4YB+ifLLXMk@FbKGz2bn zU>t!Dz>g+D4F)QBn7LE11wmdwZ{`%J=gBYt7%{kvU$(u=;dn3*!1N8`OEogW=1=3o zlygUy?>JgaLaV_QR8B+)`guLz`N&TKhl%G@3e>IOasykS&xJ7lH2Bp+cISrGYF?cj zT9X#M(o|PdMU?McCaPP0KN*bAI&d?$6t)i`imp}v-5V4Tt*h0V8OL<5*1!myQpu@J z1Fen0>J~$%FKDo^yun)Cd-2wpqTTVhzTRx!r}n2bab4cj<@S-=ocMDGT7f7?9HFCk z39i_(%6Na)5)0FGQE@!MfCdJEks2RmzFu6QG*9kRt@Hqxvx4MYJ?{d_e|hg7D@JV&w0DkP+}=n!1_&ASddzvCNhqLsd-%53~nCabPluxq+>SZ zL=xbF#YC!hBmSAN%jK*Q4d!b6ex!-dZ+rW5{4Sn=?g1!*5W4I7@e#>cK6FoEpOAei z6fkKm#SQozaIyXu_>*q}Z*mcBnbORQ&1wiyUA{vvYR=VFUU83B!ZYzBpF3a1_eGKU z;a5;}+0xs@h9&!sX6LT#sF|nFOl_PyscOQ0E7B+)qL%=2g3bIlgHkcSp+Ug zVd$Fs2JjC29kjwWh#OTwM!wC%*F~*`5v!V0HFMfL?p&RzB_97)kM`|SGSl!K|GE*s zUmfxz??cB?-aALc)WoAtWM{7GtXQb4>us4e5i(=rKjY3r&is6{xpvO)!i_wyxlB?T z9F@}_%(JFZwA8!b`%F$mARl7EV0AkKqC zcw7a@ng<~M_Aq3tB9=+HPXMF}*dVbD$R^`T@M!{)hYpf^C$|QcJ1Hj(fZr3Dv{PX4 z_46>Sa_bCv5pD93Lu42bKX(`@@thQ#kp~mA)|?)ymX_Y#mEVQ`@H(9s19Z+jZQgzzWgaer&hZVAM3NM>bHI$YXT;mEw z(2tgTkit>WKvRCTt024Ll1r{c?6tS8$L|Ar)%1}Y>7%GZWPy_oa`>iP5!KKb0KQyL z`DjaCaVw}k2yGmII58!}br%BH+%y{Hw-2ZTgkxB1@OqMnmq3(^*(G6taf(V{=t9N@ zGK0z?K!j*OIJ1!1FAceR^)(2rT4VGf&$Fbj<(}r!WZH#YLN4+lGB1-o0%jo3IyR#uFRx_e_76+gqWYquh9a1Xru%fU zSduw+%bWT5(Kpq2FMWOFjjh*x`st4klsh%_H99-GxT5EEJTg9x_k=W5a`y|*?cVZ; zV`L@bHm*Q7xF5z_(T=>T#}Z`=Yhw5kv~=j8mE}RqDt^R{V1ISPGL5*j!~-mPYI?In zsYC|%w(d=ihqfQJh5{`mDA49z$mQXYr$R=(xe%WruZ2&iEyEaXSs=QCuo+0aIz~i9LrEMPas^}J*eD$V zYmrIlC)RX26%h_HN;~Yg0qMkXW6Y{~)=3cg=g)DysMX=$)kju6jF0zN0%y!EvN38~ z*M)3#VLaJh{YafTu()k%ZPk@6(K3fiN*5&Q+QPiyX%w!n`Bz0{Ye}jDAD5gSBmJV* zi*~kmAp!r;-HJCyV`yLTdA?b%)kN`Pv~cO&J{`sLmRq|yD~I=@eaTFT&U$v-3J14# zoNH!!I;P{R&;`+U4rIMRB!$ly3DSE<){;MJW}A;hMLWAoIw0Ewh&j-YxA8kU3Gf(l z*6VYiHHjaPJh>7UoLidZMidz}GP8#<1VbZ49SD?^kHe@cWR@zXJFB*P-(SxtEHf=J5}?7U@klHPf0S{RP?l{ z`Yf3D`sW2E_~+p)ezVIIQkX7!mNuw-g{nZ<=cnk8Enb((>It>s_7J3S$beObeoW;-?^(B*pZRK_7VkrA zN@^bXb7elRK~GV6^Dhu6PU*jME}o5Es;($CKVaeTQ8il7wB6X%)`M>u{*c}{vWxs( zi#lkHma-M5I$BcoA%-ID4r}U@3%P^re9*Q|2BfZy5J~wfK)1LRuu6a}!PE+{9fUR| z!uH@Jw;xa^EN{uTnM|IMFs!EKY##DXj$4k&NJP*X6?UL{$_pz9qV$m`=TTk=Hv*2F zo2f}30-u9!hFi&Ay|U9Doa*zECz3@j$RFSX0hLe%3~KJ+;78eiz48&hrLvdaIH2~M z+M63SH}{q#JK8#=*<$w=tJUGok0%}5N|X-G!V*uu5>b>`m=|3UMnyhC?+rqs1NKC3>K~n=zF;eNKa8IA9FfiSdnCWSp%G`@q zH}0ryX>>iFN%y%sdpht&-*Ai`CT)w-v{H{#erKY#*>PTf_D`W_Y3KRA-Eij9Jle zfioIXag7GiLn|ywWgWpA!++$ifqo}h_Nu|(>oUMKxff7OeouNHnwbo|(e8|diA7!R z|1k85ndnbWeP|x^TBKicf3sg8oDiAG2jZqdv;r@)O2zAJsdG4CIUa>i0PE{M+QLpE7oZ?dX zc2g~y+0#CkYp!p!gQ~lst<&wvmsXvqTtzP{T)y6~G8Pxu(*rN?=##ZCy^n8K>D&hw zf(w}L)=Ty=^jE9i+EDh{O-EvfVm_M*9nG^l9PZVXYM*Xt+U#cw^GX6v3Gy#;6_XO* zqc5G6+|>3&NNMcM?)gV(LhoCCowizw56?Jq{FS3q-omNL>zGWk?HTk()l$2rLIX(m zj`870lS^CcNYH>-(eEDLB&r-{rCQV#1cRTWk9lNB$3YW1Vd3(2cTGb>e8UBIJ_%`S z3-DX3+1Hj1pSx_i8WxuPJAztdJ&EZSt;TsJ+NVUSJ1#sZdKsmuB5gM)Y}Pf(xYOw? zc^Zvty|`?Pm3IjF#R0F9FEu(7qANb-1lGDsS&PxFh{Z};#;=YkJdtEk)QA3npSX^z zDW{#D0Z7rV0H@Td8ec=i!4SSek2{Fh(>l%o9L5beJL6zIm;&hr&`$Ue8_{PVluODL z(BLcx8B_?!yUYRt`V4w*>OGBs(}50H@dx+=tM)j{-IE4rjC)w-S#8xmX5j+r>JiqA zPf(QC`@>q@Bai6V$zaSSyIHI;=}!EcdDm`UMp5hahT*_Xa_rkBu)aos643@|K6^<_ z2br&BQX|xR`l@b>+H?Gl_A7OuEj!$qR*#q*-amJiG)F?fI7I5sGT%A!SC^J4n z&tunvzzTS#oJ+|Zx&l07qV#rZFO*jQNL_S7`4w^$0gl-nnG zOEs5YyJUV<tJFXT3OjDlp1PkjS+_Oo>LBs##W9$pyOKSl= zPASmW={kVZ@C7nDnb(_AHNN)5Fc=AD zo)|%M?tLI4C~Ka_O8{N?vp=?djv7!EdKH&FwR_KFkMBPJNoqRYm&MdL(6le2*lZSG zc>>MF*AJfn6Yb1lWcfJJ_6Ph0oV?`uwtt}4QPu9pAKSD0sV8&TW#91MviHJ>vB0=3 z1)qPCad9fVOU~$u0uU1lQK6L|Sq+ygws;6m3^>GYAzl{xRRsS}=ESgXv;ex`4Fc3>8McFqh`IVXEA z#23GhccXduT68A!#9OLjl~%QLT5+6u<0bSadiUAk#^1En3DjO*sPD*TK`Yirod;;y zj{z3*c}w>$e&U^v84A}lSINBZB=;(Nzl<5|kg+ssbGCKaj84>jAfeNz8RPg8WoD&9SECiL1?dMC#~LZeBhv+He zLF*F~0r}zOEx;2X=0~}wO4Bm^<`xyQY0?DmCL3${@Vv1oK;nX^=&n?TKk3OS#f`?{cNHAv65M95;MBiy1MA| z_I8F{7w^UT3(i0P0{R17{U~L4;>VTfMm!ymRtL}#{CoU3YB+CT5#ZJT28MFO5&%@5 zRur?;7W)n6SYf1@%}hMxT!e9qpTy~btjZ|}p3}Nu-XUPD}`5clLCc+t8_Hy=sBGQ?D`9$1b7l5#51suG`X_y3$F7STv)}I?aOw5ViMyGe?4wj8y5Pi@y)~U* zQ&%>XKYPif1!w}e(+<^V-=zX;U!DE5=BvTfl0}6*&{Z&&F5o`^9BaZW3&G0X19|D^ zz#4ipJpE~0^K>mLZRE)W2_E9WFQH#8V0t5*6ChK-ssT&|-eB}CV3k3HS15ql8L)cv z0I!$=6gWw?B~!%O)OvcJP?@y6^^R5@e>*h|$e&0@%=c_XGN z3Y=SKP~$E+ursK(`_8@(pTO_o{u`EV+j2kRK<|1Ozq6uy`OuW5-3zPh=ge%X#|zai zrl9~5s8rABx;xXejJj+({8QD%6LmggWxWuH2QAiQgFOoPoolntQq^b|+C$Z6pT=v^ zbP8op!hLVaVw6SGe)#RyxXK~zJb-RNzOP?eG-=BLJPkLlSu$((l+7Eb&R95o^SqY! zjy6lL;*ZQsgV%%{N^}v~Dm0|iq>Wuovj;e{+RnXd;NQX?3Qbo946|`8Ad945- zPV{K+@YC2&z=G_6jDW>5+D-#x-JU`4n^|bCQN0F11ptc??1E(>K)k~BJV-1u$}SXw zHUktb5NKn8t^(yYl*2LtQAhpV*(MLOm&P4d{ytoK&+3GI5fGbXr*$ZLrtOi-LciaHPt;>?;sHYW3cP0pj zg_(hTh|djCVVs&jVJ?MOrvS_v#l+K;{7TSx5GVuCJ{hp)1W+pDv(P??a5bQN_zwrk zy2{J@uMI14J(_V|?LZ$j|E!TopiMhW-#Gl{%A4_$KR&mAgWh}QvU8g1k#fg$x^W7? zqOgf?7wkt5=(nKTSxvd^|I?9dEh|T1#}wxbtx^D!#k?gOW9KmDE0?Z>#FF^C!Ksr^80cH* zyGDlax0yN9F1dK-+{tl!6QW(&MG9Ln}+~nYQL7 zP53vu&X)I5cC^M*aQ1|AI(bF46D*#2wP*FGQ{%nT9ikLzt_Z6w^1N~gutG*a(s6

D;lqR_ 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ðQP5*h_K=;T6=E&zRE!rUS#ztQUdrj5taGy~lwb@RUrh*r!+! zxZ47T{-;TY_2SI~m}<%^wy&-V4Q`#{O7g?+_fna?ySpRa`Z{l`HMC3K1#iH}Kn>fTuHG?xaklCy>Y>f&TV~ItF3rYz z3>j!Wrl-B}%;dp}(LdN%!(_W*-8-oUuu_Vvwd)47)j30XbDHH|Z~qqc-+G6S#&uku z$1$bl=B)<7LTU^%QW3!lqKi{1uQt?&l^(s0KI#Kjn0Od+@UX>$AJMM?Q3mU!!f|!% zXq@zI_^d&IakIj+?rbSuF^#&ubmFMNvtY9s<%o?YF^VV~q~+A;v7^+7w1-3b_|3}v z5DUlY$V7|f@)KDIDhY3=mcV_%zd?OSzE120>UAaf<2VG1U*pB7LuQ+Y3n*eKgG091 zaY(z08HR^d1-uH>zRpBX zv7R;Z1y#i%B84R&9#?SmoN!)re1AxjSB&~9hrlQN!c6LDLtY_u$|#01GMEN@)a&Gn z#M%E+tO6B$d8`6_?J$!WFh?3JjWNnI1!m|oesxS8*sIF;Utm�anKPEziV$6k^p% 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

Y-EX2 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 AoB#j- diff --git a/documentation/src/docs/asciidoc/resources/themes/junit-pdf-theme.yml b/documentation/src/docs/asciidoc/resources/themes/junit-pdf-theme.yml deleted file mode 100644 index 1cba8c427dee..000000000000 --- a/documentation/src/docs/asciidoc/resources/themes/junit-pdf-theme.yml +++ /dev/null @@ -1,6 +0,0 @@ -extends: default -font: - catalog: - merge: true - Symbola: Symbola.ttf - fallbacks: [Symbola] diff --git a/documentation/src/docs/asciidoc/resources/themes/rouge_junit.rb b/documentation/src/docs/asciidoc/resources/themes/rouge_junit.rb deleted file mode 100644 index 003a88b51955..000000000000 --- a/documentation/src/docs/asciidoc/resources/themes/rouge_junit.rb +++ /dev/null @@ -1,148 +0,0 @@ -require 'rouge' unless defined? ::Rouge.version - -module Rouge; module Themes - - class JUnit < CSSTheme - name 'junit' - - # This is an extension of the official "github" theme to remove accessibility issues in code blocks - # Primer primitives (https://github.com/primer/primitives/tree/main/src/tokens) - P_RED_0 = {:light => '#ffebe9', :dark => '#ffdcd7'} - P_RED_3 = {:dark => '#ff7b72'} - P_RED_5 = {:light => '#cf222e'} - P_RED_7 = {:light => '#82071e', :dark => '#8e1519'} - P_RED_8 = {:dark => '#67060c'} - P_ORANGE_2 = {:dark => '#ffa657'} - P_ORANGE_6 = {:light => '#953800'} - P_GREEN_0 = {:light => '#dafbe1', :dark => '#aff5b4'} - P_GREEN_1 = {:dark => '#7ee787'} - P_GREEN_6 = {:light => '#116329'} - P_GREEN_8 = {:dark => '#033a16'} - P_BLUE_1 = {:dark => '#a5d6ff'} - P_BLUE_2 = {:dark => '#79c0ff'} - P_BLUE_5 = {:dark => '#1f6feb'} - P_BLUE_6 = {:light => '#0550ae'} - P_BLUE_7 = {:light => '#055099'} - P_BLUE_8 = {:light => '#0a3069'} - P_PURPLE_2 = {:dark => '#d2a8ff'} - P_PURPLE_5 = {:light => '#8250df'} - P_GRAY_0 = {:light => '#f6f8fa', :dark => '#f0f6fc'} - P_GRAY_1 = {:dark => '#c9d1d9'} - P_GRAY_3 = {:dark => '#8b949e'} - P_GRAY_5 = {:light => '#34383d'} # '#6e7781' - P_GRAY_8 = {:dark => '#161b22'} - P_GRAY_9 = {:light => '#24292f'} - - extend HasModes - - def self.light! - mode :dark # indicate that there is a dark variant - mode! :light - end - - def self.dark! - mode :light # indicate that there is a light variant - mode! :dark - end - - def self.make_dark! - palette :comment => P_GRAY_3[@mode] - palette :constant => P_BLUE_2[@mode] - palette :entity => P_PURPLE_2[@mode] - palette :heading => P_BLUE_5[@mode] - palette :keyword => P_RED_3[@mode] - palette :string => P_BLUE_1[@mode] - palette :tag => P_GREEN_1[@mode] - palette :variable => P_ORANGE_2[@mode] - - palette :fgDefault => P_GRAY_1[@mode] - palette :bgDefault => P_GRAY_8[@mode] - - palette :fgInserted => P_GREEN_0[@mode] - palette :bgInserted => P_GREEN_8[@mode] - - palette :fgDeleted => P_RED_0[@mode] - palette :bgDeleted => P_RED_8[@mode] - - palette :fgError => P_GRAY_0[@mode] - palette :bgError => P_RED_7[@mode] - end - - def self.make_light! - palette :comment => P_GREEN_6[@mode] - palette :constant => P_BLUE_6[@mode] - palette :entity => P_PURPLE_5[@mode] - palette :heading => P_BLUE_6[@mode] - palette :keyword => P_RED_5[@mode] - palette :string => P_BLUE_8[@mode] - palette :tag => P_BLUE_7[@mode] - palette :variable => P_ORANGE_6[@mode] - - palette :fgDefault => P_GRAY_9[@mode] - palette :bgDefault => P_GRAY_0[@mode] - - palette :fgInserted => P_GREEN_6[@mode] - palette :bgInserted => P_GREEN_0[@mode] - - palette :fgDeleted => P_RED_7[@mode] - palette :bgDeleted => P_RED_0[@mode] - - palette :fgError => P_GRAY_0[@mode] - palette :bgError => P_RED_7[@mode] - end - - light! - - style Text, :fg => :fgDefault, :bg => :bgDefault - - style Keyword, :fg => :keyword - - style Generic::Error, :fg => :fgError - - style Generic::Deleted, :fg => :fgDeleted, :bg => :bgDeleted - - style Name::Builtin, - Name::Class, - Name::Constant, - Name::Namespace, :fg => :variable - - style Literal::String::Regex, - Name::Attribute, - Name::Tag, :fg => :tag - - style Generic::Inserted, :fg => :fgInserted, :bg => :bgInserted - - style Keyword::Constant, - Literal, - Literal::String::Backtick, - Name::Builtin::Pseudo, - Name::Exception, - Name::Label, - Name::Property, - Name::Variable, - Operator, :fg => :constant - - style Generic::Heading, - Generic::Subheading, :fg => :heading, :bold => true - - style Literal::String, :fg => :string - - style Name::Decorator, - Name::Function, :fg => :entity - - style Error, :fg => :fgError, :bg => :bgError - - style Comment, - Generic::Lineno, - Generic::Traceback, :fg => :comment - - style Name::Entity, - Literal::String::Interpol, :fg => :fgDefault - - style Generic::Emph, :fg => :fgDefault, :italic => true - - style Generic::Strong, :fg => :fgDefault, :bold => true - - end -end; end - diff --git a/documentation/src/docs/asciidoc/tocbot-3.0.2/styles.css b/documentation/src/docs/asciidoc/tocbot-3.0.2/styles.css deleted file mode 100644 index 3fd131d89c5d..000000000000 --- a/documentation/src/docs/asciidoc/tocbot-3.0.2/styles.css +++ /dev/null @@ -1 +0,0 @@ -.transition--300{transition:all 300ms ease-in-out}.toc{height:100%;width:280px;transform:translateX(0)}.content h1:first-child,.content h2:first-child{padding-top:0;margin-top:0}.title{font-size:3em}.content{margin-bottom:95vh}.content ul,.content ol{list-style:inherit}.content a{color:#0977c3;text-decoration:none;border-bottom:1px solid #EEE;transition:all 300ms ease}.content a.no-decoration{border-bottom:0}.content a:hover{border-bottom:1px solid #0977c3}.content a:hover.no-decoration{border-bottom:0}a.toc-link{text-decoration:none}.try-it-container{transform:translateY(84%)}.try-it-container.is-open{transform:translateY(0%)}.page-content{display:block !important}.hljs{display:block;background:white;padding:0.5em;color:#333333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-string,.hljs-variable,.hljs-template-variable,.hljs-strong,.hljs-emphasis,.hljs-quote{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-literal,.hljs-symbol,.hljs-bullet,.hljs-attribute{color:#0086b3}.hljs-section,.hljs-name{color:#63a35c}.hljs-tag{color:#333333}.hljs-title,.hljs-attr,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:#795da3}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline}.toc-icon{position:fixed;top:0;right:0}#toc:checked ~ .toc{box-shadow:0 0 5px #c8c8c8;transform:translateX(0)}.toc{background-color:rgba(255,255,255,0.9);transform:translateX(-100%)}.toc.toc-right{transform:translateX(100%);right:0}@media (min-width: 52em){.toc{transform:translateX(0)}.toc.toc-right{transform:translateX(0);right:calc((100% - 48rem - 4rem) / 2)}.toc-icon{display:none}.try-it-container{display:block}.content{margin-left:280px}.toc-right ~ .content{margin-left:0;margin-right:280px}}*{box-sizing:border-box}body{font-size:1.2rem;font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif}h1,h2,h3,h4,h5,h6{padding-top:0.5em}p{margin-top:0.25rem}pre{display:block;background:#f7f7f7;border-radius:2px;border:1px solid #e0e0e0;padding:2px;line-height:1.2;margin-bottom:10px;overflow:auto;white-space:pre-wrap}code{display:inline;font-size:.8em;max-width:100%} diff --git a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.css b/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.css deleted file mode 100644 index 6265223f15ad..000000000000 --- a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.css +++ /dev/null @@ -1 +0,0 @@ -.toc{overflow-y:auto}.toc>ul{overflow:hidden;position:relative}.toc>ul li{list-style:none}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#EEE;content:' ';display:inline-block;height:inherit;left:0;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B} diff --git a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.js b/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.js deleted file mode 100644 index 52fe18378f4f..000000000000 --- a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.js +++ /dev/null @@ -1,136 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 5); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/* unknown exports provided */ -/* all exports used */ -/*!***********************************!*\ - !*** (webpack)/buildin/global.js ***! - \***********************************/ -/***/ (function(module, exports) { - -eval("var g;\r\n\r\n// This works in non-strict mode\r\ng = (function() {\r\n\treturn this;\r\n})();\r\n\r\ntry {\r\n\t// This works if eval is allowed (see CSP)\r\n\tg = g || Function(\"return this\")() || (1,eval)(\"this\");\r\n} catch(e) {\r\n\t// This works if the window reference is available\r\n\tif(typeof window === \"object\")\r\n\t\tg = window;\r\n}\r\n\r\n// g can still be undefined, but nothing to do about it...\r\n// We return undefined, instead of nothing here, so it's\r\n// easier to handle this case. if(!global) { ...}\r\n\r\nmodule.exports = g;\r\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8od2VicGFjaykvYnVpbGRpbi9nbG9iYWwuanM/MzY5OCJdLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgZztcclxuXHJcbi8vIFRoaXMgd29ya3MgaW4gbm9uLXN0cmljdCBtb2RlXHJcbmcgPSAoZnVuY3Rpb24oKSB7XHJcblx0cmV0dXJuIHRoaXM7XHJcbn0pKCk7XHJcblxyXG50cnkge1xyXG5cdC8vIFRoaXMgd29ya3MgaWYgZXZhbCBpcyBhbGxvd2VkIChzZWUgQ1NQKVxyXG5cdGcgPSBnIHx8IEZ1bmN0aW9uKFwicmV0dXJuIHRoaXNcIikoKSB8fCAoMSxldmFsKShcInRoaXNcIik7XHJcbn0gY2F0Y2goZSkge1xyXG5cdC8vIFRoaXMgd29ya3MgaWYgdGhlIHdpbmRvdyByZWZlcmVuY2UgaXMgYXZhaWxhYmxlXHJcblx0aWYodHlwZW9mIHdpbmRvdyA9PT0gXCJvYmplY3RcIilcclxuXHRcdGcgPSB3aW5kb3c7XHJcbn1cclxuXHJcbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cclxuLy8gV2UgcmV0dXJuIHVuZGVmaW5lZCwgaW5zdGVhZCBvZiBub3RoaW5nIGhlcmUsIHNvIGl0J3NcclxuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBnO1xyXG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAod2VicGFjaykvYnVpbGRpbi9nbG9iYWwuanNcbi8vIG1vZHVsZSBpZCA9IDBcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Iiwic291cmNlUm9vdCI6IiJ9"); - -/***/ }), -/* 1 */ -/* unknown exports provided */ -/* all exports used */ -/*!**********************************!*\ - !*** ./~/zenscroll/zenscroll.js ***! - \**********************************/ -/***/ (function(module, exports, __webpack_require__) { - -eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**\n * Zenscroll 4.0.0\n * https://github.com/zengabor/zenscroll/\n *\n * Copyright 2015–2017 Gabor Lenard\n *\n * This is free and unencumbered software released into the public domain.\n * \n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n * \n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n * \n * For more information, please refer to \n * \n */\n\n/*jshint devel:true, asi:true */\n\n/*global define, module */\n\n\n(function (root, factory) {\n\tif (true) {\n\t\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory()),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))\n\t} else if (typeof module === \"object\" && module.exports) {\n\t\tmodule.exports = factory()\n\t} else {\n\t\t(function install() {\n\t\t\t// To make sure Zenscroll can be referenced from the header, before `body` is available\n\t\t\tif (document && document.body) {\n\t\t\t\troot.zenscroll = factory()\n\t\t\t} else {\n\t\t\t\t// retry 9ms later\n\t\t\t\tsetTimeout(install, 9)\n\t\t\t}\n\t\t})()\n\t}\n}(this, function () {\n\t\"use strict\"\n\n\n\t// Detect if the browser already supports native smooth scrolling (e.g., Firefox 36+ and Chrome 49+) and it is enabled:\n\tvar isNativeSmoothScrollEnabledOn = function (elem) {\n\t\treturn (\"getComputedStyle\" in window) &&\n\t\t\twindow.getComputedStyle(elem)[\"scroll-behavior\"] === \"smooth\"\n\t}\n\n\n\t// Exit if it’s not a browser environment:\n\tif (typeof window === \"undefined\" || !(\"document\" in window)) {\n\t\treturn {}\n\t}\n\n\n\tvar makeScroller = function (container, defaultDuration, edgeOffset) {\n\n\t\t// Use defaults if not provided\n\t\tdefaultDuration = defaultDuration || 999 //ms\n\t\tif (!edgeOffset && edgeOffset !== 0) {\n\t\t\t// When scrolling, this amount of distance is kept from the edges of the container:\n\t\t\tedgeOffset = 9 //px\n\t\t}\n\n\t\t// Handling the life-cycle of the scroller\n\t\tvar scrollTimeoutId\n\t\tvar setScrollTimeoutId = function (newValue) {\n\t\t\tscrollTimeoutId = newValue\n\t\t}\n\n\t\t/**\n\t\t * Stop the current smooth scroll operation immediately\n\t\t */\n\t\tvar stopScroll = function () {\n\t\t\tclearTimeout(scrollTimeoutId)\n\t\t\tsetScrollTimeoutId(0)\n\t\t}\n\n\t\tvar getTopWithEdgeOffset = function (elem) {\n\t\t\treturn Math.max(0, container.getTopOf(elem) - edgeOffset)\n\t\t}\n\n\t\t/**\n\t\t * Scrolls to a specific vertical position in the document.\n\t\t *\n\t\t * @param {targetY} The vertical position within the document.\n\t\t * @param {duration} Optionally the duration of the scroll operation.\n\t\t * If not provided the default duration is used.\n\t\t * @param {onDone} An optional callback function to be invoked once the scroll finished.\n\t\t */\n\t\tvar scrollToY = function (targetY, duration, onDone) {\n\t\t\tstopScroll()\n\t\t\tif (duration === 0 || (duration && duration < 0) || isNativeSmoothScrollEnabledOn(container.body)) {\n\t\t\t\tcontainer.toY(targetY)\n\t\t\t\tif (onDone) {\n\t\t\t\t\tonDone()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar startY = container.getY()\n\t\t\t\tvar distance = Math.max(0, targetY) - startY\n\t\t\t\tvar startTime = new Date().getTime()\n\t\t\t\tduration = duration || Math.min(Math.abs(distance), defaultDuration);\n\t\t\t\t(function loopScroll() {\n\t\t\t\t\tsetScrollTimeoutId(setTimeout(function () {\n\t\t\t\t\t\t// Calculate percentage:\n\t\t\t\t\t\tvar p = Math.min(1, (new Date().getTime() - startTime) / duration)\n\t\t\t\t\t\t// Calculate the absolute vertical position:\n\t\t\t\t\t\tvar y = Math.max(0, Math.floor(startY + distance*(p < 0.5 ? 2*p*p : p*(4 - p*2)-1)))\n\t\t\t\t\t\tcontainer.toY(y)\n\t\t\t\t\t\tif (p < 1 && (container.getHeight() + y) < container.body.scrollHeight) {\n\t\t\t\t\t\t\tloopScroll()\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetTimeout(stopScroll, 99) // with cooldown time\n\t\t\t\t\t\t\tif (onDone) {\n\t\t\t\t\t\t\t\tonDone()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 9))\n\t\t\t\t})()\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Scrolls to the top of a specific element.\n\t\t *\n\t\t * @param {elem} The element to scroll to.\n\t\t * @param {duration} Optionally the duration of the scroll operation.\n\t\t * @param {onDone} An optional callback function to be invoked once the scroll finished.\n\t\t */\n\t\tvar scrollToElem = function (elem, duration, onDone) {\n\t\t\tscrollToY(getTopWithEdgeOffset(elem), duration, onDone)\n\t\t}\n\n\t\t/**\n\t\t * Scrolls an element into view if necessary.\n\t\t *\n\t\t * @param {elem} The element.\n\t\t * @param {duration} Optionally the duration of the scroll operation.\n\t\t * @param {onDone} An optional callback function to be invoked once the scroll finished.\n\t\t */\n\t\tvar scrollIntoView = function (elem, duration, onDone) {\n\t\t\tvar elemHeight = elem.getBoundingClientRect().height\n\t\t\tvar elemBottom = container.getTopOf(elem) + elemHeight\n\t\t\tvar containerHeight = container.getHeight()\n\t\t\tvar y = container.getY()\n\t\t\tvar containerBottom = y + containerHeight\n\t\t\tif (getTopWithEdgeOffset(elem) < y || (elemHeight + edgeOffset) > containerHeight) {\n\t\t\t\t// Element is clipped at top or is higher than screen.\n\t\t\t\tscrollToElem(elem, duration, onDone)\n\t\t\t} else if ((elemBottom + edgeOffset) > containerBottom) {\n\t\t\t\t// Element is clipped at the bottom.\n\t\t\t\tscrollToY(elemBottom - containerHeight + edgeOffset, duration, onDone)\n\t\t\t} else if (onDone) {\n\t\t\t\tonDone()\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Scrolls to the center of an element.\n\t\t *\n\t\t * @param {elem} The element.\n\t\t * @param {duration} Optionally the duration of the scroll operation.\n\t\t * @param {offset} Optionally the offset of the top of the element from the center of the screen.\n\t\t * @param {onDone} An optional callback function to be invoked once the scroll finished.\n\t\t */\n\t\tvar scrollToCenterOf = function (elem, duration, offset, onDone) {\n\t\t\tscrollToY(Math.max(0, container.getTopOf(elem) - container.getHeight()/2 + (offset || elem.getBoundingClientRect().height/2)), duration, onDone)\n\t\t}\n\n\t\t/**\n\t\t * Changes default settings for this scroller.\n\t\t *\n\t\t * @param {newDefaultDuration} Optionally a new value for default duration, used for each scroll method by default.\n\t\t * Ignored if null or undefined.\n\t\t * @param {newEdgeOffset} Optionally a new value for the edge offset, used by each scroll method by default. Ignored if null or undefined.\n\t\t * @returns An object with the current values.\n\t\t */\n\t\tvar setup = function (newDefaultDuration, newEdgeOffset) {\n\t\t\tif (newDefaultDuration === 0 || newDefaultDuration) {\n\t\t\t\tdefaultDuration = newDefaultDuration\n\t\t\t}\n\t\t\tif (newEdgeOffset === 0 || newEdgeOffset) {\n\t\t\t\tedgeOffset = newEdgeOffset\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdefaultDuration: defaultDuration,\n\t\t\t\tedgeOffset: edgeOffset\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tsetup: setup,\n\t\t\tto: scrollToElem,\n\t\t\ttoY: scrollToY,\n\t\t\tintoView: scrollIntoView,\n\t\t\tcenter: scrollToCenterOf,\n\t\t\tstop: stopScroll,\n\t\t\tmoving: function () { return !!scrollTimeoutId },\n\t\t\tgetY: container.getY,\n\t\t\tgetTopOf: container.getTopOf\n\t\t}\n\n\t}\n\n\n\tvar docElem = document.documentElement\n\tvar getDocY = function () { return window.scrollY || docElem.scrollTop }\n\n\t// Create a scroller for the document:\n\tvar zenscroll = makeScroller({\n\t\tbody: document.scrollingElement || document.body,\n\t\ttoY: function (y) { window.scrollTo(0, y) },\n\t\tgetY: getDocY,\n\t\tgetHeight: function () { return window.innerHeight || docElem.clientHeight },\n\t\tgetTopOf: function (elem) { return elem.getBoundingClientRect().top + getDocY() - docElem.offsetTop }\n\t})\n\n\n\t/**\n\t * Creates a scroller from the provided container element (e.g., a DIV)\n\t *\n\t * @param {scrollContainer} The vertical position within the document.\n\t * @param {defaultDuration} Optionally a value for default duration, used for each scroll method by default.\n\t * Ignored if 0 or null or undefined.\n\t * @param {edgeOffset} Optionally a value for the edge offset, used by each scroll method by default. \n\t * Ignored if null or undefined.\n\t * @returns A scroller object, similar to `zenscroll` but controlling the provided element.\n\t */\n\tzenscroll.createScroller = function (scrollContainer, defaultDuration, edgeOffset) {\n\t\treturn makeScroller({\n\t\t\tbody: scrollContainer,\n\t\t\ttoY: function (y) { scrollContainer.scrollTop = y },\n\t\t\tgetY: function () { return scrollContainer.scrollTop },\n\t\t\tgetHeight: function () { return Math.min(scrollContainer.clientHeight, window.innerHeight || docElem.clientHeight) },\n\t\t\tgetTopOf: function (elem) { return elem.offsetTop }\n\t\t}, defaultDuration, edgeOffset)\n\t}\n\n\n\t// Automatic link-smoothing on achors\n\t// Exclude IE8- or when native is enabled or Zenscroll auto- is disabled\n\tif (\"addEventListener\" in window && !window.noZensmooth && !isNativeSmoothScrollEnabledOn(document.body)) {\n\n\n\t\tvar isScrollRestorationSupported = \"scrollRestoration\" in history\n\n\t\t// On first load & refresh make sure the browser restores the position first\n\t\tif (isScrollRestorationSupported) {\n\t\t\thistory.scrollRestoration = \"auto\"\n\t\t}\n\n\t\twindow.addEventListener(\"load\", function () {\n\n\t\t\tif (isScrollRestorationSupported) {\n\t\t\t\t// Set it to manual\n\t\t\t\tsetTimeout(function () { history.scrollRestoration = \"manual\" }, 9)\n\t\t\t\twindow.addEventListener(\"popstate\", function (event) {\n\t\t\t\t\tif (event.state && \"zenscrollY\" in event.state) {\n\t\t\t\t\t\tzenscroll.toY(event.state.zenscrollY)\n\t\t\t\t\t}\n\t\t\t\t}, false)\n\t\t\t}\n\n\t\t\t// Add edge offset on first load if necessary\n\t\t\t// This may not work on IE (or older computer?) as it requires more timeout, around 100 ms\n\t\t\tif (window.location.hash) {\n\t\t\t\tsetTimeout(function () {\n\t\t\t\t\t// Adjustment is only needed if there is an edge offset:\n\t\t\t\t\tvar edgeOffset = zenscroll.setup().edgeOffset\n\t\t\t\t\tif (edgeOffset) {\n\t\t\t\t\t\tvar targetElem = document.getElementById(window.location.href.split(\"#\")[1])\n\t\t\t\t\t\tif (targetElem) {\n\t\t\t\t\t\t\tvar targetY = Math.max(0, zenscroll.getTopOf(targetElem) - edgeOffset)\n\t\t\t\t\t\t\tvar diff = zenscroll.getY() - targetY\n\t\t\t\t\t\t\t// Only do the adjustment if the browser is very close to the element:\n\t\t\t\t\t\t\tif (0 <= diff && diff < 9 ) {\n\t\t\t\t\t\t\t\twindow.scrollTo(0, targetY)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 9)\n\t\t\t}\n\n\t\t}, false)\n\n\t\t// Handling clicks on anchors\n\t\tvar RE_noZensmooth = new RegExp(\"(^|\\\\s)noZensmooth(\\\\s|$)\")\n\t\twindow.addEventListener(\"click\", function (event) {\n\t\t\tvar anchor = event.target\n\t\t\twhile (anchor && anchor.tagName !== \"A\") {\n\t\t\t\tanchor = anchor.parentNode\n\t\t\t}\n\t\t\t// Let the browser handle the click if it wasn't with the primary button, or with some modifier keys:\n\t\t\tif (!anchor || event.which !== 1 || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Save the current scrolling position so it can be used for scroll restoration:\n\t\t\tif (isScrollRestorationSupported) {\n\t\t\t\ttry {\n\t\t\t\t\thistory.replaceState({ zenscrollY: zenscroll.getY() }, \"\")\n\t\t\t\t} catch (e) {\n\t\t\t\t\t// Avoid the Chrome Security exception on file protocol, e.g., file://index.html\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Find the referenced ID:\n\t\t\tvar href = anchor.getAttribute(\"href\") || \"\"\n\t\t\tif (href.indexOf(\"#\") === 0 && !RE_noZensmooth.test(anchor.className)) {\n\t\t\t\tvar targetY = 0\n\t\t\t\tvar targetElem = document.getElementById(href.substring(1))\n\t\t\t\tif (href !== \"#\") {\n\t\t\t\t\tif (!targetElem) {\n\t\t\t\t\t\t// Let the browser handle the click if the target ID is not found.\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\ttargetY = zenscroll.getTopOf(targetElem)\n\t\t\t\t}\n\t\t\t\tevent.preventDefault()\n\t\t\t\t// By default trigger the browser's `hashchange` event...\n\t\t\t\tvar onDone = function () { window.location = href }\n\t\t\t\t// ...unless there is an edge offset specified\n\t\t\t\tvar edgeOffset = zenscroll.setup().edgeOffset\n\t\t\t\tif (edgeOffset) {\n\t\t\t\t\ttargetY = Math.max(0, targetY - edgeOffset)\n\t\t\t\t\tonDone = function () { history.pushState(null, \"\", href) }\n\t\t\t\t}\n\t\t\t\tzenscroll.toY(targetY, null, onDone)\n\t\t\t}\n\t\t}, false)\n\n\t}\n\n\n\treturn zenscroll\n\n\n}));\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL34vemVuc2Nyb2xsL3plbnNjcm9sbC5qcz8yNzMyIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogWmVuc2Nyb2xsIDQuMC4wXG4gKiBodHRwczovL2dpdGh1Yi5jb20vemVuZ2Fib3IvemVuc2Nyb2xsL1xuICpcbiAqIENvcHlyaWdodCAyMDE14oCTMjAxNyBHYWJvciBMZW5hcmRcbiAqXG4gKiBUaGlzIGlzIGZyZWUgYW5kIHVuZW5jdW1iZXJlZCBzb2Z0d2FyZSByZWxlYXNlZCBpbnRvIHRoZSBwdWJsaWMgZG9tYWluLlxuICogXG4gKiBBbnlvbmUgaXMgZnJlZSB0byBjb3B5LCBtb2RpZnksIHB1Ymxpc2gsIHVzZSwgY29tcGlsZSwgc2VsbCwgb3JcbiAqIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSwgZWl0aGVyIGluIHNvdXJjZSBjb2RlIGZvcm0gb3IgYXMgYSBjb21waWxlZFxuICogYmluYXJ5LCBmb3IgYW55IHB1cnBvc2UsIGNvbW1lcmNpYWwgb3Igbm9uLWNvbW1lcmNpYWwsIGFuZCBieSBhbnlcbiAqIG1lYW5zLlxuICogXG4gKiBJbiBqdXJpc2RpY3Rpb25zIHRoYXQgcmVjb2duaXplIGNvcHlyaWdodCBsYXdzLCB0aGUgYXV0aG9yIG9yIGF1dGhvcnNcbiAqIG9mIHRoaXMgc29mdHdhcmUgZGVkaWNhdGUgYW55IGFuZCBhbGwgY29weXJpZ2h0IGludGVyZXN0IGluIHRoZVxuICogc29mdHdhcmUgdG8gdGhlIHB1YmxpYyBkb21haW4uIFdlIG1ha2UgdGhpcyBkZWRpY2F0aW9uIGZvciB0aGUgYmVuZWZpdFxuICogb2YgdGhlIHB1YmxpYyBhdCBsYXJnZSBhbmQgdG8gdGhlIGRldHJpbWVudCBvZiBvdXIgaGVpcnMgYW5kXG4gKiBzdWNjZXNzb3JzLiBXZSBpbnRlbmQgdGhpcyBkZWRpY2F0aW9uIHRvIGJlIGFuIG92ZXJ0IGFjdCBvZlxuICogcmVsaW5xdWlzaG1lbnQgaW4gcGVycGV0dWl0eSBvZiBhbGwgcHJlc2VudCBhbmQgZnV0dXJlIHJpZ2h0cyB0byB0aGlzXG4gKiBzb2Z0d2FyZSB1bmRlciBjb3B5cmlnaHQgbGF3LlxuICogXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELFxuICogRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GXG4gKiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUlxuICogT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsXG4gKiBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1JcbiAqIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cbiAqIFxuICogRm9yIG1vcmUgaW5mb3JtYXRpb24sIHBsZWFzZSByZWZlciB0byA8aHR0cDovL3VubGljZW5zZS5vcmc+XG4gKiBcbiAqL1xuXG4vKmpzaGludCBkZXZlbDp0cnVlLCBhc2k6dHJ1ZSAqL1xuXG4vKmdsb2JhbCBkZWZpbmUsIG1vZHVsZSAqL1xuXG5cbihmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuXHRpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcblx0XHRkZWZpbmUoW10sIGZhY3RvcnkoKSlcblx0fSBlbHNlIGlmICh0eXBlb2YgbW9kdWxlID09PSBcIm9iamVjdFwiICYmIG1vZHVsZS5leHBvcnRzKSB7XG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KClcblx0fSBlbHNlIHtcblx0XHQoZnVuY3Rpb24gaW5zdGFsbCgpIHtcblx0XHRcdC8vIFRvIG1ha2Ugc3VyZSBaZW5zY3JvbGwgY2FuIGJlIHJlZmVyZW5jZWQgZnJvbSB0aGUgaGVhZGVyLCBiZWZvcmUgYGJvZHlgIGlzIGF2YWlsYWJsZVxuXHRcdFx0aWYgKGRvY3VtZW50ICYmIGRvY3VtZW50LmJvZHkpIHtcblx0XHRcdFx0cm9vdC56ZW5zY3JvbGwgPSBmYWN0b3J5KClcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIHJldHJ5IDltcyBsYXRlclxuXHRcdFx0XHRzZXRUaW1lb3V0KGluc3RhbGwsIDkpXG5cdFx0XHR9XG5cdFx0fSkoKVxuXHR9XG59KHRoaXMsIGZ1bmN0aW9uICgpIHtcblx0XCJ1c2Ugc3RyaWN0XCJcblxuXG5cdC8vIERldGVjdCBpZiB0aGUgYnJvd3NlciBhbHJlYWR5IHN1cHBvcnRzIG5hdGl2ZSBzbW9vdGggc2Nyb2xsaW5nIChlLmcuLCBGaXJlZm94IDM2KyBhbmQgQ2hyb21lIDQ5KykgYW5kIGl0IGlzIGVuYWJsZWQ6XG5cdHZhciBpc05hdGl2ZVNtb290aFNjcm9sbEVuYWJsZWRPbiA9IGZ1bmN0aW9uIChlbGVtKSB7XG5cdFx0cmV0dXJuIChcImdldENvbXB1dGVkU3R5bGVcIiBpbiB3aW5kb3cpICYmXG5cdFx0XHR3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbGVtKVtcInNjcm9sbC1iZWhhdmlvclwiXSA9PT0gXCJzbW9vdGhcIlxuXHR9XG5cblxuXHQvLyBFeGl0IGlmIGl04oCZcyBub3QgYSBicm93c2VyIGVudmlyb25tZW50OlxuXHRpZiAodHlwZW9mIHdpbmRvdyA9PT0gXCJ1bmRlZmluZWRcIiB8fCAhKFwiZG9jdW1lbnRcIiBpbiB3aW5kb3cpKSB7XG5cdFx0cmV0dXJuIHt9XG5cdH1cblxuXG5cdHZhciBtYWtlU2Nyb2xsZXIgPSBmdW5jdGlvbiAoY29udGFpbmVyLCBkZWZhdWx0RHVyYXRpb24sIGVkZ2VPZmZzZXQpIHtcblxuXHRcdC8vIFVzZSBkZWZhdWx0cyBpZiBub3QgcHJvdmlkZWRcblx0XHRkZWZhdWx0RHVyYXRpb24gPSBkZWZhdWx0RHVyYXRpb24gfHwgOTk5IC8vbXNcblx0XHRpZiAoIWVkZ2VPZmZzZXQgJiYgZWRnZU9mZnNldCAhPT0gMCkge1xuXHRcdFx0Ly8gV2hlbiBzY3JvbGxpbmcsIHRoaXMgYW1vdW50IG9mIGRpc3RhbmNlIGlzIGtlcHQgZnJvbSB0aGUgZWRnZXMgb2YgdGhlIGNvbnRhaW5lcjpcblx0XHRcdGVkZ2VPZmZzZXQgPSA5IC8vcHhcblx0XHR9XG5cblx0XHQvLyBIYW5kbGluZyB0aGUgbGlmZS1jeWNsZSBvZiB0aGUgc2Nyb2xsZXJcblx0XHR2YXIgc2Nyb2xsVGltZW91dElkXG5cdFx0dmFyIHNldFNjcm9sbFRpbWVvdXRJZCA9IGZ1bmN0aW9uIChuZXdWYWx1ZSkge1xuXHRcdFx0c2Nyb2xsVGltZW91dElkID0gbmV3VmFsdWVcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBTdG9wIHRoZSBjdXJyZW50IHNtb290aCBzY3JvbGwgb3BlcmF0aW9uIGltbWVkaWF0ZWx5XG5cdFx0ICovXG5cdFx0dmFyIHN0b3BTY3JvbGwgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRjbGVhclRpbWVvdXQoc2Nyb2xsVGltZW91dElkKVxuXHRcdFx0c2V0U2Nyb2xsVGltZW91dElkKDApXG5cdFx0fVxuXG5cdFx0dmFyIGdldFRvcFdpdGhFZGdlT2Zmc2V0ID0gZnVuY3Rpb24gKGVsZW0pIHtcblx0XHRcdHJldHVybiBNYXRoLm1heCgwLCBjb250YWluZXIuZ2V0VG9wT2YoZWxlbSkgLSBlZGdlT2Zmc2V0KVxuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIFNjcm9sbHMgdG8gYSBzcGVjaWZpYyB2ZXJ0aWNhbCBwb3NpdGlvbiBpbiB0aGUgZG9jdW1lbnQuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge3RhcmdldFl9IFRoZSB2ZXJ0aWNhbCBwb3NpdGlvbiB3aXRoaW4gdGhlIGRvY3VtZW50LlxuXHRcdCAqIEBwYXJhbSB7ZHVyYXRpb259IE9wdGlvbmFsbHkgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY3JvbGwgb3BlcmF0aW9uLlxuXHRcdCAqICAgICAgICBJZiBub3QgcHJvdmlkZWQgdGhlIGRlZmF1bHQgZHVyYXRpb24gaXMgdXNlZC5cblx0XHQgKiBAcGFyYW0ge29uRG9uZX0gQW4gb3B0aW9uYWwgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBvbmNlIHRoZSBzY3JvbGwgZmluaXNoZWQuXG5cdFx0ICovXG5cdFx0dmFyIHNjcm9sbFRvWSA9IGZ1bmN0aW9uICh0YXJnZXRZLCBkdXJhdGlvbiwgb25Eb25lKSB7XG5cdFx0XHRzdG9wU2Nyb2xsKClcblx0XHRcdGlmIChkdXJhdGlvbiA9PT0gMCB8fCAoZHVyYXRpb24gJiYgZHVyYXRpb24gPCAwKSB8fCBpc05hdGl2ZVNtb290aFNjcm9sbEVuYWJsZWRPbihjb250YWluZXIuYm9keSkpIHtcblx0XHRcdFx0Y29udGFpbmVyLnRvWSh0YXJnZXRZKVxuXHRcdFx0XHRpZiAob25Eb25lKSB7XG5cdFx0XHRcdFx0b25Eb25lKClcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIHN0YXJ0WSA9IGNvbnRhaW5lci5nZXRZKClcblx0XHRcdFx0dmFyIGRpc3RhbmNlID0gTWF0aC5tYXgoMCwgdGFyZ2V0WSkgLSBzdGFydFlcblx0XHRcdFx0dmFyIHN0YXJ0VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpXG5cdFx0XHRcdGR1cmF0aW9uID0gZHVyYXRpb24gfHwgTWF0aC5taW4oTWF0aC5hYnMoZGlzdGFuY2UpLCBkZWZhdWx0RHVyYXRpb24pO1xuXHRcdFx0XHQoZnVuY3Rpb24gbG9vcFNjcm9sbCgpIHtcblx0XHRcdFx0XHRzZXRTY3JvbGxUaW1lb3V0SWQoc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHQvLyBDYWxjdWxhdGUgcGVyY2VudGFnZTpcblx0XHRcdFx0XHRcdHZhciBwID0gTWF0aC5taW4oMSwgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnRUaW1lKSAvIGR1cmF0aW9uKVxuXHRcdFx0XHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBhYnNvbHV0ZSB2ZXJ0aWNhbCBwb3NpdGlvbjpcblx0XHRcdFx0XHRcdHZhciB5ID0gTWF0aC5tYXgoMCwgTWF0aC5mbG9vcihzdGFydFkgKyBkaXN0YW5jZSoocCA8IDAuNSA/IDIqcCpwIDogcCooNCAtIHAqMiktMSkpKVxuXHRcdFx0XHRcdFx0Y29udGFpbmVyLnRvWSh5KVxuXHRcdFx0XHRcdFx0aWYgKHAgPCAxICYmIChjb250YWluZXIuZ2V0SGVpZ2h0KCkgKyB5KSA8IGNvbnRhaW5lci5ib2R5LnNjcm9sbEhlaWdodCkge1xuXHRcdFx0XHRcdFx0XHRsb29wU2Nyb2xsKClcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHNldFRpbWVvdXQoc3RvcFNjcm9sbCwgOTkpIC8vIHdpdGggY29vbGRvd24gdGltZVxuXHRcdFx0XHRcdFx0XHRpZiAob25Eb25lKSB7XG5cdFx0XHRcdFx0XHRcdFx0b25Eb25lKClcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0sIDkpKVxuXHRcdFx0XHR9KSgpXG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogU2Nyb2xscyB0byB0aGUgdG9wIG9mIGEgc3BlY2lmaWMgZWxlbWVudC5cblx0XHQgKlxuXHRcdCAqIEBwYXJhbSB7ZWxlbX0gVGhlIGVsZW1lbnQgdG8gc2Nyb2xsIHRvLlxuXHRcdCAqIEBwYXJhbSB7ZHVyYXRpb259IE9wdGlvbmFsbHkgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY3JvbGwgb3BlcmF0aW9uLlxuXHRcdCAqIEBwYXJhbSB7b25Eb25lfSBBbiBvcHRpb25hbCBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIG9uY2UgdGhlIHNjcm9sbCBmaW5pc2hlZC5cblx0XHQgKi9cblx0XHR2YXIgc2Nyb2xsVG9FbGVtID0gZnVuY3Rpb24gKGVsZW0sIGR1cmF0aW9uLCBvbkRvbmUpIHtcblx0XHRcdHNjcm9sbFRvWShnZXRUb3BXaXRoRWRnZU9mZnNldChlbGVtKSwgZHVyYXRpb24sIG9uRG9uZSlcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBTY3JvbGxzIGFuIGVsZW1lbnQgaW50byB2aWV3IGlmIG5lY2Vzc2FyeS5cblx0XHQgKlxuXHRcdCAqIEBwYXJhbSB7ZWxlbX0gVGhlIGVsZW1lbnQuXG5cdFx0ICogQHBhcmFtIHtkdXJhdGlvbn0gT3B0aW9uYWxseSB0aGUgZHVyYXRpb24gb2YgdGhlIHNjcm9sbCBvcGVyYXRpb24uXG5cdFx0ICogQHBhcmFtIHtvbkRvbmV9IEFuIG9wdGlvbmFsIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgb25jZSB0aGUgc2Nyb2xsIGZpbmlzaGVkLlxuXHRcdCAqL1xuXHRcdHZhciBzY3JvbGxJbnRvVmlldyA9IGZ1bmN0aW9uIChlbGVtLCBkdXJhdGlvbiwgb25Eb25lKSB7XG5cdFx0XHR2YXIgZWxlbUhlaWdodCA9IGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0XG5cdFx0XHR2YXIgZWxlbUJvdHRvbSA9IGNvbnRhaW5lci5nZXRUb3BPZihlbGVtKSArIGVsZW1IZWlnaHRcblx0XHRcdHZhciBjb250YWluZXJIZWlnaHQgPSBjb250YWluZXIuZ2V0SGVpZ2h0KClcblx0XHRcdHZhciB5ID0gY29udGFpbmVyLmdldFkoKVxuXHRcdFx0dmFyIGNvbnRhaW5lckJvdHRvbSA9IHkgKyBjb250YWluZXJIZWlnaHRcblx0XHRcdGlmIChnZXRUb3BXaXRoRWRnZU9mZnNldChlbGVtKSA8IHkgfHwgKGVsZW1IZWlnaHQgKyBlZGdlT2Zmc2V0KSA+IGNvbnRhaW5lckhlaWdodCkge1xuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGNsaXBwZWQgYXQgdG9wIG9yIGlzIGhpZ2hlciB0aGFuIHNjcmVlbi5cblx0XHRcdFx0c2Nyb2xsVG9FbGVtKGVsZW0sIGR1cmF0aW9uLCBvbkRvbmUpXG5cdFx0XHR9IGVsc2UgaWYgKChlbGVtQm90dG9tICsgZWRnZU9mZnNldCkgPiBjb250YWluZXJCb3R0b20pIHtcblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBjbGlwcGVkIGF0IHRoZSBib3R0b20uXG5cdFx0XHRcdHNjcm9sbFRvWShlbGVtQm90dG9tIC0gY29udGFpbmVySGVpZ2h0ICsgZWRnZU9mZnNldCwgZHVyYXRpb24sIG9uRG9uZSlcblx0XHRcdH0gZWxzZSBpZiAob25Eb25lKSB7XG5cdFx0XHRcdG9uRG9uZSgpXG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogU2Nyb2xscyB0byB0aGUgY2VudGVyIG9mIGFuIGVsZW1lbnQuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge2VsZW19IFRoZSBlbGVtZW50LlxuXHRcdCAqIEBwYXJhbSB7ZHVyYXRpb259IE9wdGlvbmFsbHkgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY3JvbGwgb3BlcmF0aW9uLlxuXHRcdCAqIEBwYXJhbSB7b2Zmc2V0fSBPcHRpb25hbGx5IHRoZSBvZmZzZXQgb2YgdGhlIHRvcCBvZiB0aGUgZWxlbWVudCBmcm9tIHRoZSBjZW50ZXIgb2YgdGhlIHNjcmVlbi5cblx0XHQgKiBAcGFyYW0ge29uRG9uZX0gQW4gb3B0aW9uYWwgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBvbmNlIHRoZSBzY3JvbGwgZmluaXNoZWQuXG5cdFx0ICovXG5cdFx0dmFyIHNjcm9sbFRvQ2VudGVyT2YgPSBmdW5jdGlvbiAoZWxlbSwgZHVyYXRpb24sIG9mZnNldCwgb25Eb25lKSB7XG5cdFx0XHRzY3JvbGxUb1koTWF0aC5tYXgoMCwgY29udGFpbmVyLmdldFRvcE9mKGVsZW0pIC0gY29udGFpbmVyLmdldEhlaWdodCgpLzIgKyAob2Zmc2V0IHx8IGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0LzIpKSwgZHVyYXRpb24sIG9uRG9uZSlcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBDaGFuZ2VzIGRlZmF1bHQgc2V0dGluZ3MgZm9yIHRoaXMgc2Nyb2xsZXIuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge25ld0RlZmF1bHREdXJhdGlvbn0gT3B0aW9uYWxseSBhIG5ldyB2YWx1ZSBmb3IgZGVmYXVsdCBkdXJhdGlvbiwgdXNlZCBmb3IgZWFjaCBzY3JvbGwgbWV0aG9kIGJ5IGRlZmF1bHQuXG5cdFx0ICogICAgICAgIElnbm9yZWQgaWYgbnVsbCBvciB1bmRlZmluZWQuXG5cdFx0ICogQHBhcmFtIHtuZXdFZGdlT2Zmc2V0fSBPcHRpb25hbGx5IGEgbmV3IHZhbHVlIGZvciB0aGUgZWRnZSBvZmZzZXQsIHVzZWQgYnkgZWFjaCBzY3JvbGwgbWV0aG9kIGJ5IGRlZmF1bHQuIElnbm9yZWQgaWYgbnVsbCBvciB1bmRlZmluZWQuXG5cdFx0ICogQHJldHVybnMgQW4gb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgdmFsdWVzLlxuXHRcdCAqL1xuXHRcdHZhciBzZXR1cCA9IGZ1bmN0aW9uIChuZXdEZWZhdWx0RHVyYXRpb24sIG5ld0VkZ2VPZmZzZXQpIHtcblx0XHRcdGlmIChuZXdEZWZhdWx0RHVyYXRpb24gPT09IDAgfHwgbmV3RGVmYXVsdER1cmF0aW9uKSB7XG5cdFx0XHRcdGRlZmF1bHREdXJhdGlvbiA9IG5ld0RlZmF1bHREdXJhdGlvblxuXHRcdFx0fVxuXHRcdFx0aWYgKG5ld0VkZ2VPZmZzZXQgPT09IDAgfHwgbmV3RWRnZU9mZnNldCkge1xuXHRcdFx0XHRlZGdlT2Zmc2V0ID0gbmV3RWRnZU9mZnNldFxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0ZGVmYXVsdER1cmF0aW9uOiBkZWZhdWx0RHVyYXRpb24sXG5cdFx0XHRcdGVkZ2VPZmZzZXQ6IGVkZ2VPZmZzZXRcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0c2V0dXA6IHNldHVwLFxuXHRcdFx0dG86IHNjcm9sbFRvRWxlbSxcblx0XHRcdHRvWTogc2Nyb2xsVG9ZLFxuXHRcdFx0aW50b1ZpZXc6IHNjcm9sbEludG9WaWV3LFxuXHRcdFx0Y2VudGVyOiBzY3JvbGxUb0NlbnRlck9mLFxuXHRcdFx0c3RvcDogc3RvcFNjcm9sbCxcblx0XHRcdG1vdmluZzogZnVuY3Rpb24gKCkgeyByZXR1cm4gISFzY3JvbGxUaW1lb3V0SWQgfSxcblx0XHRcdGdldFk6IGNvbnRhaW5lci5nZXRZLFxuXHRcdFx0Z2V0VG9wT2Y6IGNvbnRhaW5lci5nZXRUb3BPZlxuXHRcdH1cblxuXHR9XG5cblxuXHR2YXIgZG9jRWxlbSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudFxuXHR2YXIgZ2V0RG9jWSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHdpbmRvdy5zY3JvbGxZIHx8IGRvY0VsZW0uc2Nyb2xsVG9wIH1cblxuXHQvLyBDcmVhdGUgYSBzY3JvbGxlciBmb3IgdGhlIGRvY3VtZW50OlxuXHR2YXIgemVuc2Nyb2xsID0gbWFrZVNjcm9sbGVyKHtcblx0XHRib2R5OiBkb2N1bWVudC5zY3JvbGxpbmdFbGVtZW50IHx8IGRvY3VtZW50LmJvZHksXG5cdFx0dG9ZOiBmdW5jdGlvbiAoeSkgeyB3aW5kb3cuc2Nyb2xsVG8oMCwgeSkgfSxcblx0XHRnZXRZOiBnZXREb2NZLFxuXHRcdGdldEhlaWdodDogZnVuY3Rpb24gKCkgeyByZXR1cm4gd2luZG93LmlubmVySGVpZ2h0IHx8IGRvY0VsZW0uY2xpZW50SGVpZ2h0IH0sXG5cdFx0Z2V0VG9wT2Y6IGZ1bmN0aW9uIChlbGVtKSB7IHJldHVybiBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCArIGdldERvY1koKSAtIGRvY0VsZW0ub2Zmc2V0VG9wIH1cblx0fSlcblxuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgc2Nyb2xsZXIgZnJvbSB0aGUgcHJvdmlkZWQgY29udGFpbmVyIGVsZW1lbnQgKGUuZy4sIGEgRElWKVxuXHQgKlxuXHQgKiBAcGFyYW0ge3Njcm9sbENvbnRhaW5lcn0gVGhlIHZlcnRpY2FsIHBvc2l0aW9uIHdpdGhpbiB0aGUgZG9jdW1lbnQuXG5cdCAqIEBwYXJhbSB7ZGVmYXVsdER1cmF0aW9ufSBPcHRpb25hbGx5IGEgdmFsdWUgZm9yIGRlZmF1bHQgZHVyYXRpb24sIHVzZWQgZm9yIGVhY2ggc2Nyb2xsIG1ldGhvZCBieSBkZWZhdWx0LlxuXHQgKiAgICAgICAgSWdub3JlZCBpZiAwIG9yIG51bGwgb3IgdW5kZWZpbmVkLlxuXHQgKiBAcGFyYW0ge2VkZ2VPZmZzZXR9IE9wdGlvbmFsbHkgYSB2YWx1ZSBmb3IgdGhlIGVkZ2Ugb2Zmc2V0LCB1c2VkIGJ5IGVhY2ggc2Nyb2xsIG1ldGhvZCBieSBkZWZhdWx0LiBcblx0ICogICAgICAgIElnbm9yZWQgaWYgbnVsbCBvciB1bmRlZmluZWQuXG5cdCAqIEByZXR1cm5zIEEgc2Nyb2xsZXIgb2JqZWN0LCBzaW1pbGFyIHRvIGB6ZW5zY3JvbGxgIGJ1dCBjb250cm9sbGluZyB0aGUgcHJvdmlkZWQgZWxlbWVudC5cblx0ICovXG5cdHplbnNjcm9sbC5jcmVhdGVTY3JvbGxlciA9IGZ1bmN0aW9uIChzY3JvbGxDb250YWluZXIsIGRlZmF1bHREdXJhdGlvbiwgZWRnZU9mZnNldCkge1xuXHRcdHJldHVybiBtYWtlU2Nyb2xsZXIoe1xuXHRcdFx0Ym9keTogc2Nyb2xsQ29udGFpbmVyLFxuXHRcdFx0dG9ZOiBmdW5jdGlvbiAoeSkgeyBzY3JvbGxDb250YWluZXIuc2Nyb2xsVG9wID0geSB9LFxuXHRcdFx0Z2V0WTogZnVuY3Rpb24gKCkgeyByZXR1cm4gc2Nyb2xsQ29udGFpbmVyLnNjcm9sbFRvcCB9LFxuXHRcdFx0Z2V0SGVpZ2h0OiBmdW5jdGlvbiAoKSB7IHJldHVybiBNYXRoLm1pbihzY3JvbGxDb250YWluZXIuY2xpZW50SGVpZ2h0LCB3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jRWxlbS5jbGllbnRIZWlnaHQpIH0sXG5cdFx0XHRnZXRUb3BPZjogZnVuY3Rpb24gKGVsZW0pIHsgcmV0dXJuIGVsZW0ub2Zmc2V0VG9wIH1cblx0XHR9LCBkZWZhdWx0RHVyYXRpb24sIGVkZ2VPZmZzZXQpXG5cdH1cblxuXG5cdC8vIEF1dG9tYXRpYyBsaW5rLXNtb290aGluZyBvbiBhY2hvcnNcblx0Ly8gRXhjbHVkZSBJRTgtIG9yIHdoZW4gbmF0aXZlIGlzIGVuYWJsZWQgb3IgWmVuc2Nyb2xsIGF1dG8tIGlzIGRpc2FibGVkXG5cdGlmIChcImFkZEV2ZW50TGlzdGVuZXJcIiBpbiB3aW5kb3cgJiYgIXdpbmRvdy5ub1plbnNtb290aCAmJiAhaXNOYXRpdmVTbW9vdGhTY3JvbGxFbmFibGVkT24oZG9jdW1lbnQuYm9keSkpIHtcblxuXG5cdFx0dmFyIGlzU2Nyb2xsUmVzdG9yYXRpb25TdXBwb3J0ZWQgPSBcInNjcm9sbFJlc3RvcmF0aW9uXCIgaW4gaGlzdG9yeVxuXG5cdFx0Ly8gT24gZmlyc3QgbG9hZCAmIHJlZnJlc2ggbWFrZSBzdXJlIHRoZSBicm93c2VyIHJlc3RvcmVzIHRoZSBwb3NpdGlvbiBmaXJzdFxuXHRcdGlmIChpc1Njcm9sbFJlc3RvcmF0aW9uU3VwcG9ydGVkKSB7XG5cdFx0XHRoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uID0gXCJhdXRvXCJcblx0XHR9XG5cblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImxvYWRcIiwgZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRpZiAoaXNTY3JvbGxSZXN0b3JhdGlvblN1cHBvcnRlZCkge1xuXHRcdFx0XHQvLyBTZXQgaXQgdG8gbWFudWFsXG5cdFx0XHRcdHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyBoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uID0gXCJtYW51YWxcIiB9LCA5KVxuXHRcdFx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInBvcHN0YXRlXCIsIGZ1bmN0aW9uIChldmVudCkge1xuXHRcdFx0XHRcdGlmIChldmVudC5zdGF0ZSAmJiBcInplbnNjcm9sbFlcIiBpbiBldmVudC5zdGF0ZSkge1xuXHRcdFx0XHRcdFx0emVuc2Nyb2xsLnRvWShldmVudC5zdGF0ZS56ZW5zY3JvbGxZKVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSwgZmFsc2UpXG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBlZGdlIG9mZnNldCBvbiBmaXJzdCBsb2FkIGlmIG5lY2Vzc2FyeVxuXHRcdFx0Ly8gVGhpcyBtYXkgbm90IHdvcmsgb24gSUUgKG9yIG9sZGVyIGNvbXB1dGVyPykgYXMgaXQgcmVxdWlyZXMgbW9yZSB0aW1lb3V0LCBhcm91bmQgMTAwIG1zXG5cdFx0XHRpZiAod2luZG93LmxvY2F0aW9uLmhhc2gpIHtcblx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0Ly8gQWRqdXN0bWVudCBpcyBvbmx5IG5lZWRlZCBpZiB0aGVyZSBpcyBhbiBlZGdlIG9mZnNldDpcblx0XHRcdFx0XHR2YXIgZWRnZU9mZnNldCA9IHplbnNjcm9sbC5zZXR1cCgpLmVkZ2VPZmZzZXRcblx0XHRcdFx0XHRpZiAoZWRnZU9mZnNldCkge1xuXHRcdFx0XHRcdFx0dmFyIHRhcmdldEVsZW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh3aW5kb3cubG9jYXRpb24uaHJlZi5zcGxpdChcIiNcIilbMV0pXG5cdFx0XHRcdFx0XHRpZiAodGFyZ2V0RWxlbSkge1xuXHRcdFx0XHRcdFx0XHR2YXIgdGFyZ2V0WSA9IE1hdGgubWF4KDAsIHplbnNjcm9sbC5nZXRUb3BPZih0YXJnZXRFbGVtKSAtIGVkZ2VPZmZzZXQpXG5cdFx0XHRcdFx0XHRcdHZhciBkaWZmID0gemVuc2Nyb2xsLmdldFkoKSAtIHRhcmdldFlcblx0XHRcdFx0XHRcdFx0Ly8gT25seSBkbyB0aGUgYWRqdXN0bWVudCBpZiB0aGUgYnJvd3NlciBpcyB2ZXJ5IGNsb3NlIHRvIHRoZSBlbGVtZW50OlxuXHRcdFx0XHRcdFx0XHRpZiAoMCA8PSBkaWZmICYmIGRpZmYgPCA5ICkge1xuXHRcdFx0XHRcdFx0XHRcdHdpbmRvdy5zY3JvbGxUbygwLCB0YXJnZXRZKVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LCA5KVxuXHRcdFx0fVxuXG5cdFx0fSwgZmFsc2UpXG5cblx0XHQvLyBIYW5kbGluZyBjbGlja3Mgb24gYW5jaG9yc1xuXHRcdHZhciBSRV9ub1plbnNtb290aCA9IG5ldyBSZWdFeHAoXCIoXnxcXFxccylub1plbnNtb290aChcXFxcc3wkKVwiKVxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgZnVuY3Rpb24gKGV2ZW50KSB7XG5cdFx0XHR2YXIgYW5jaG9yID0gZXZlbnQudGFyZ2V0XG5cdFx0XHR3aGlsZSAoYW5jaG9yICYmIGFuY2hvci50YWdOYW1lICE9PSBcIkFcIikge1xuXHRcdFx0XHRhbmNob3IgPSBhbmNob3IucGFyZW50Tm9kZVxuXHRcdFx0fVxuXHRcdFx0Ly8gTGV0IHRoZSBicm93c2VyIGhhbmRsZSB0aGUgY2xpY2sgaWYgaXQgd2Fzbid0IHdpdGggdGhlIHByaW1hcnkgYnV0dG9uLCBvciB3aXRoIHNvbWUgbW9kaWZpZXIga2V5czpcblx0XHRcdGlmICghYW5jaG9yIHx8IGV2ZW50LndoaWNoICE9PSAxIHx8IGV2ZW50LnNoaWZ0S2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSB8fCBldmVudC5hbHRLZXkpIHtcblx0XHRcdFx0cmV0dXJuXG5cdFx0XHR9XG5cdFx0XHQvLyBTYXZlIHRoZSBjdXJyZW50IHNjcm9sbGluZyBwb3NpdGlvbiBzbyBpdCBjYW4gYmUgdXNlZCBmb3Igc2Nyb2xsIHJlc3RvcmF0aW9uOlxuXHRcdFx0aWYgKGlzU2Nyb2xsUmVzdG9yYXRpb25TdXBwb3J0ZWQpIHtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRoaXN0b3J5LnJlcGxhY2VTdGF0ZSh7IHplbnNjcm9sbFk6IHplbnNjcm9sbC5nZXRZKCkgfSwgXCJcIilcblx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdC8vIEF2b2lkIHRoZSBDaHJvbWUgU2VjdXJpdHkgZXhjZXB0aW9uIG9uIGZpbGUgcHJvdG9jb2wsIGUuZy4sIGZpbGU6Ly9pbmRleC5odG1sXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdC8vIEZpbmQgdGhlIHJlZmVyZW5jZWQgSUQ6XG5cdFx0XHR2YXIgaHJlZiA9IGFuY2hvci5nZXRBdHRyaWJ1dGUoXCJocmVmXCIpIHx8IFwiXCJcblx0XHRcdGlmIChocmVmLmluZGV4T2YoXCIjXCIpID09PSAwICYmICFSRV9ub1plbnNtb290aC50ZXN0KGFuY2hvci5jbGFzc05hbWUpKSB7XG5cdFx0XHRcdHZhciB0YXJnZXRZID0gMFxuXHRcdFx0XHR2YXIgdGFyZ2V0RWxlbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGhyZWYuc3Vic3RyaW5nKDEpKVxuXHRcdFx0XHRpZiAoaHJlZiAhPT0gXCIjXCIpIHtcblx0XHRcdFx0XHRpZiAoIXRhcmdldEVsZW0pIHtcblx0XHRcdFx0XHRcdC8vIExldCB0aGUgYnJvd3NlciBoYW5kbGUgdGhlIGNsaWNrIGlmIHRoZSB0YXJnZXQgSUQgaXMgbm90IGZvdW5kLlxuXHRcdFx0XHRcdFx0cmV0dXJuXG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRhcmdldFkgPSB6ZW5zY3JvbGwuZ2V0VG9wT2YodGFyZ2V0RWxlbSlcblx0XHRcdFx0fVxuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpXG5cdFx0XHRcdC8vIEJ5IGRlZmF1bHQgdHJpZ2dlciB0aGUgYnJvd3NlcidzIGBoYXNoY2hhbmdlYCBldmVudC4uLlxuXHRcdFx0XHR2YXIgb25Eb25lID0gZnVuY3Rpb24gKCkgeyB3aW5kb3cubG9jYXRpb24gPSBocmVmIH1cblx0XHRcdFx0Ly8gLi4udW5sZXNzIHRoZXJlIGlzIGFuIGVkZ2Ugb2Zmc2V0IHNwZWNpZmllZFxuXHRcdFx0XHR2YXIgZWRnZU9mZnNldCA9IHplbnNjcm9sbC5zZXR1cCgpLmVkZ2VPZmZzZXRcblx0XHRcdFx0aWYgKGVkZ2VPZmZzZXQpIHtcblx0XHRcdFx0XHR0YXJnZXRZID0gTWF0aC5tYXgoMCwgdGFyZ2V0WSAtIGVkZ2VPZmZzZXQpXG5cdFx0XHRcdFx0b25Eb25lID0gZnVuY3Rpb24gKCkgeyBoaXN0b3J5LnB1c2hTdGF0ZShudWxsLCBcIlwiLCBocmVmKSB9XG5cdFx0XHRcdH1cblx0XHRcdFx0emVuc2Nyb2xsLnRvWSh0YXJnZXRZLCBudWxsLCBvbkRvbmUpXG5cdFx0XHR9XG5cdFx0fSwgZmFsc2UpXG5cblx0fVxuXG5cblx0cmV0dXJuIHplbnNjcm9sbFxuXG5cbn0pKTtcblxuXG5cbi8vLy8vLy8vLy8vLy8vLy8vL1xuLy8gV0VCUEFDSyBGT09URVJcbi8vIC4vfi96ZW5zY3JvbGwvemVuc2Nyb2xsLmpzXG4vLyBtb2R1bGUgaWQgPSAxXG4vLyBtb2R1bGUgY2h1bmtzID0gMCJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Iiwic291cmNlUm9vdCI6IiJ9"); - -/***/ }), -/* 2 */ -/* unknown exports provided */ -/* all exports used */ -/*!******************************!*\ - !*** ./src/js/build-html.js ***! - \******************************/ -/***/ (function(module, exports) { - -eval("/**\n * This file is responsible for building the DOM and updating DOM state.\n *\n * @author Tim Scanlin\n */\n\nmodule.exports = function (options) {\n var forEach = [].forEach\n var some = [].some\n var body = document.body\n var currentlyHighlighting = true\n var SPACE_CHAR = ' '\n\n /**\n * Create link and list elements.\n * @param {Object} d\n * @param {HTMLElement} container\n * @return {HTMLElement}\n */\n function createEl (d, container) {\n var link = container.appendChild(createLink(d))\n if (d.children.length) {\n var list = createList(d.isCollapsed)\n d.children.forEach(function (child) {\n createEl(child, list)\n })\n link.appendChild(list)\n }\n }\n\n /**\n * Render nested heading array data into a given selector.\n * @param {String} selector\n * @param {Array} data\n * @return {HTMLElement}\n */\n function render (selector, data) {\n var collapsed = false\n var container = createList(collapsed)\n\n data.forEach(function (d) {\n createEl(d, container)\n })\n\n var parent = document.querySelector(selector)\n\n // Return if no parent is found.\n if (parent === null) {\n return\n }\n\n // Remove existing child if it exists.\n if (parent.firstChild) {\n parent.removeChild(parent.firstChild)\n }\n\n // Append the Elements that have been created;\n return parent.appendChild(container)\n }\n\n /**\n * Create link element.\n * @param {Object} data\n * @return {HTMLElement}\n */\n function createLink (data) {\n var item = document.createElement('li')\n var a = document.createElement('a')\n if (options.listItemClass) {\n item.setAttribute('class', options.listItemClass)\n }\n if (options.includeHtml && data.childNodes.length) {\n forEach.call(data.childNodes, function (node) {\n a.appendChild(node.cloneNode(true))\n })\n } else {\n // Default behavior.\n a.textContent = data.textContent\n }\n a.setAttribute('href', '#' + data.id)\n a.setAttribute('class', options.linkClass +\n SPACE_CHAR + 'node-name--' + data.nodeName +\n SPACE_CHAR + options.extraLinkClasses)\n item.appendChild(a)\n return item\n }\n\n /**\n * Create list element.\n * @param {Boolean} isCollapsed\n * @return {HTMLElement}\n */\n function createList (isCollapsed) {\n var list = document.createElement('ul')\n var classes = options.listClass +\n SPACE_CHAR + options.extraListClasses\n if (isCollapsed) {\n classes += SPACE_CHAR + options.collapsibleClass\n classes += SPACE_CHAR + options.isCollapsedClass\n }\n list.setAttribute('class', classes)\n return list\n }\n\n /**\n * Update fixed sidebar class.\n * @return {HTMLElement}\n */\n function updateFixedSidebarClass () {\n var top = document.documentElement.scrollTop || body.scrollTop\n var posFixedEl = document.querySelector(options.positionFixedSelector)\n\n if (options.fixedSidebarOffset === 'auto') {\n options.fixedSidebarOffset = document.querySelector(options.tocSelector).offsetTop\n }\n\n if (top > options.fixedSidebarOffset) {\n if (posFixedEl.className.indexOf(options.positionFixedClass) === -1) {\n posFixedEl.className += SPACE_CHAR + options.positionFixedClass\n }\n } else {\n posFixedEl.className = posFixedEl.className.split(SPACE_CHAR + options.positionFixedClass).join('')\n }\n }\n\n /**\n * Update TOC highlighting and collpased groupings.\n */\n function updateToc (headingsArray) {\n var top = document.documentElement.scrollTop || body.scrollTop\n\n // Add fixed class at offset;\n if (options.positionFixedSelector) {\n updateFixedSidebarClass()\n }\n\n // Get the top most heading currently visible on the page so we know what to highlight.\n var headings = headingsArray\n var topHeader\n // Using some instead of each so that we can escape early.\n if (currentlyHighlighting &&\n document.querySelector(options.tocSelector) !== null &&\n headings.length > 0) {\n some.call(headings, function (heading, i) {\n if (heading.offsetTop > top + options.headingsOffset + 10) {\n // Don't allow negative index value.\n var index = (i === 0) ? i : i - 1\n topHeader = headings[index]\n return true\n } else if (i === headings.length - 1) {\n // This allows scrolling for the last heading on the page.\n topHeader = headings[headings.length - 1]\n return true\n }\n })\n\n // Remove the active class from the other tocLinks.\n var tocLinks = document.querySelector(options.tocSelector)\n .querySelectorAll('.' + options.linkClass)\n forEach.call(tocLinks, function (tocLink) {\n tocLink.className = tocLink.className.split(SPACE_CHAR + options.activeLinkClass).join('')\n })\n\n // Add the active class to the active tocLink.\n var activeTocLink = document.querySelector(options.tocSelector)\n .querySelector('.' + options.linkClass +\n '.node-name--' + topHeader.nodeName +\n '[href=\"#' + topHeader.id + '\"]')\n activeTocLink.className += SPACE_CHAR + options.activeLinkClass\n\n var tocLists = document.querySelector(options.tocSelector)\n .querySelectorAll('.' + options.listClass + '.' + options.collapsibleClass)\n\n // Collapse the other collapsible lists.\n forEach.call(tocLists, function (list) {\n var collapsedClass = SPACE_CHAR + options.isCollapsedClass\n if (list.className.indexOf(collapsedClass) === -1) {\n list.className += SPACE_CHAR + options.isCollapsedClass\n }\n })\n\n // Expand the active link's collapsible list and its sibling if applicable.\n if (activeTocLink.nextSibling) {\n activeTocLink.nextSibling.className = activeTocLink.nextSibling.className.split(SPACE_CHAR + options.isCollapsedClass).join('')\n }\n removeCollapsedFromParents(activeTocLink.parentNode.parentNode)\n }\n }\n\n /**\n * Remove collpased class from parent elements.\n * @param {HTMLElement} element\n * @return {HTMLElement}\n */\n function removeCollapsedFromParents (element) {\n if (element.className.indexOf(options.collapsibleClass) !== -1) {\n element.className = element.className.split(SPACE_CHAR + options.isCollapsedClass).join('')\n return removeCollapsedFromParents(element.parentNode.parentNode)\n }\n return element\n }\n\n /**\n * Disable TOC Animation when a link is clicked.\n * @param {Event} event\n */\n function disableTocAnimation (event) {\n var target = event.target || event.srcElement\n if (typeof target.className !== 'string' || target.className.indexOf(options.linkClass) === -1) {\n return\n }\n // Bind to tocLink clicks to temporarily disable highlighting\n // while smoothScroll is animating.\n currentlyHighlighting = false\n }\n\n /**\n * Enable TOC Animation.\n */\n function enableTocAnimation () {\n currentlyHighlighting = true\n }\n\n return {\n enableTocAnimation: enableTocAnimation,\n disableTocAnimation: disableTocAnimation,\n render: render,\n updateToc: updateToc\n }\n}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMi5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3NyYy9qcy9idWlsZC1odG1sLmpzPzdkMDEiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIGJ1aWxkaW5nIHRoZSBET00gYW5kIHVwZGF0aW5nIERPTSBzdGF0ZS5cbiAqXG4gKiBAYXV0aG9yIFRpbSBTY2FubGluXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICB2YXIgZm9yRWFjaCA9IFtdLmZvckVhY2hcbiAgdmFyIHNvbWUgPSBbXS5zb21lXG4gIHZhciBib2R5ID0gZG9jdW1lbnQuYm9keVxuICB2YXIgY3VycmVudGx5SGlnaGxpZ2h0aW5nID0gdHJ1ZVxuICB2YXIgU1BBQ0VfQ0hBUiA9ICcgJ1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgbGluayBhbmQgbGlzdCBlbGVtZW50cy5cbiAgICogQHBhcmFtIHtPYmplY3R9IGRcbiAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gY29udGFpbmVyXG4gICAqIEByZXR1cm4ge0hUTUxFbGVtZW50fVxuICAgKi9cbiAgZnVuY3Rpb24gY3JlYXRlRWwgKGQsIGNvbnRhaW5lcikge1xuICAgIHZhciBsaW5rID0gY29udGFpbmVyLmFwcGVuZENoaWxkKGNyZWF0ZUxpbmsoZCkpXG4gICAgaWYgKGQuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICB2YXIgbGlzdCA9IGNyZWF0ZUxpc3QoZC5pc0NvbGxhcHNlZClcbiAgICAgIGQuY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICAgICAgY3JlYXRlRWwoY2hpbGQsIGxpc3QpXG4gICAgICB9KVxuICAgICAgbGluay5hcHBlbmRDaGlsZChsaXN0KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXIgbmVzdGVkIGhlYWRpbmcgYXJyYXkgZGF0YSBpbnRvIGEgZ2l2ZW4gc2VsZWN0b3IuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZWxlY3RvclxuICAgKiBAcGFyYW0ge0FycmF5fSBkYXRhXG4gICAqIEByZXR1cm4ge0hUTUxFbGVtZW50fVxuICAgKi9cbiAgZnVuY3Rpb24gcmVuZGVyIChzZWxlY3RvciwgZGF0YSkge1xuICAgIHZhciBjb2xsYXBzZWQgPSBmYWxzZVxuICAgIHZhciBjb250YWluZXIgPSBjcmVhdGVMaXN0KGNvbGxhcHNlZClcblxuICAgIGRhdGEuZm9yRWFjaChmdW5jdGlvbiAoZCkge1xuICAgICAgY3JlYXRlRWwoZCwgY29udGFpbmVyKVxuICAgIH0pXG5cbiAgICB2YXIgcGFyZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihzZWxlY3RvcilcblxuICAgIC8vIFJldHVybiBpZiBubyBwYXJlbnQgaXMgZm91bmQuXG4gICAgaWYgKHBhcmVudCA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIGV4aXN0aW5nIGNoaWxkIGlmIGl0IGV4aXN0cy5cbiAgICBpZiAocGFyZW50LmZpcnN0Q2hpbGQpIHtcbiAgICAgIHBhcmVudC5yZW1vdmVDaGlsZChwYXJlbnQuZmlyc3RDaGlsZClcbiAgICB9XG5cbiAgICAvLyBBcHBlbmQgdGhlIEVsZW1lbnRzIHRoYXQgaGF2ZSBiZWVuIGNyZWF0ZWQ7XG4gICAgcmV0dXJuIHBhcmVudC5hcHBlbmRDaGlsZChjb250YWluZXIpXG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGxpbmsgZWxlbWVudC5cbiAgICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAgICogQHJldHVybiB7SFRNTEVsZW1lbnR9XG4gICAqL1xuICBmdW5jdGlvbiBjcmVhdGVMaW5rIChkYXRhKSB7XG4gICAgdmFyIGl0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpXG4gICAgdmFyIGEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJylcbiAgICBpZiAob3B0aW9ucy5saXN0SXRlbUNsYXNzKSB7XG4gICAgICBpdGVtLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCBvcHRpb25zLmxpc3RJdGVtQ2xhc3MpXG4gICAgfVxuICAgIGlmIChvcHRpb25zLmluY2x1ZGVIdG1sICYmIGRhdGEuY2hpbGROb2Rlcy5sZW5ndGgpIHtcbiAgICAgIGZvckVhY2guY2FsbChkYXRhLmNoaWxkTm9kZXMsIGZ1bmN0aW9uIChub2RlKSB7XG4gICAgICAgIGEuYXBwZW5kQ2hpbGQobm9kZS5jbG9uZU5vZGUodHJ1ZSkpXG4gICAgICB9KVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEZWZhdWx0IGJlaGF2aW9yLlxuICAgICAgYS50ZXh0Q29udGVudCA9IGRhdGEudGV4dENvbnRlbnRcbiAgICB9XG4gICAgYS5zZXRBdHRyaWJ1dGUoJ2hyZWYnLCAnIycgKyBkYXRhLmlkKVxuICAgIGEuc2V0QXR0cmlidXRlKCdjbGFzcycsIG9wdGlvbnMubGlua0NsYXNzICtcbiAgICAgIFNQQUNFX0NIQVIgKyAnbm9kZS1uYW1lLS0nICsgZGF0YS5ub2RlTmFtZSArXG4gICAgICBTUEFDRV9DSEFSICsgb3B0aW9ucy5leHRyYUxpbmtDbGFzc2VzKVxuICAgIGl0ZW0uYXBwZW5kQ2hpbGQoYSlcbiAgICByZXR1cm4gaXRlbVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBsaXN0IGVsZW1lbnQuXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNDb2xsYXBzZWRcbiAgICogQHJldHVybiB7SFRNTEVsZW1lbnR9XG4gICAqL1xuICBmdW5jdGlvbiBjcmVhdGVMaXN0IChpc0NvbGxhcHNlZCkge1xuICAgIHZhciBsaXN0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKVxuICAgIHZhciBjbGFzc2VzID0gb3B0aW9ucy5saXN0Q2xhc3MgK1xuICAgICAgU1BBQ0VfQ0hBUiArIG9wdGlvbnMuZXh0cmFMaXN0Q2xhc3Nlc1xuICAgIGlmIChpc0NvbGxhcHNlZCkge1xuICAgICAgY2xhc3NlcyArPSBTUEFDRV9DSEFSICsgb3B0aW9ucy5jb2xsYXBzaWJsZUNsYXNzXG4gICAgICBjbGFzc2VzICs9IFNQQUNFX0NIQVIgKyBvcHRpb25zLmlzQ29sbGFwc2VkQ2xhc3NcbiAgICB9XG4gICAgbGlzdC5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgY2xhc3NlcylcbiAgICByZXR1cm4gbGlzdFxuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZSBmaXhlZCBzaWRlYmFyIGNsYXNzLlxuICAgKiBAcmV0dXJuIHtIVE1MRWxlbWVudH1cbiAgICovXG4gIGZ1bmN0aW9uIHVwZGF0ZUZpeGVkU2lkZWJhckNsYXNzICgpIHtcbiAgICB2YXIgdG9wID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCB8fCBib2R5LnNjcm9sbFRvcFxuICAgIHZhciBwb3NGaXhlZEVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihvcHRpb25zLnBvc2l0aW9uRml4ZWRTZWxlY3RvcilcblxuICAgIGlmIChvcHRpb25zLmZpeGVkU2lkZWJhck9mZnNldCA9PT0gJ2F1dG8nKSB7XG4gICAgICBvcHRpb25zLmZpeGVkU2lkZWJhck9mZnNldCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iob3B0aW9ucy50b2NTZWxlY3Rvcikub2Zmc2V0VG9wXG4gICAgfVxuXG4gICAgaWYgKHRvcCA+IG9wdGlvbnMuZml4ZWRTaWRlYmFyT2Zmc2V0KSB7XG4gICAgICBpZiAocG9zRml4ZWRFbC5jbGFzc05hbWUuaW5kZXhPZihvcHRpb25zLnBvc2l0aW9uRml4ZWRDbGFzcykgPT09IC0xKSB7XG4gICAgICAgIHBvc0ZpeGVkRWwuY2xhc3NOYW1lICs9IFNQQUNFX0NIQVIgKyBvcHRpb25zLnBvc2l0aW9uRml4ZWRDbGFzc1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBwb3NGaXhlZEVsLmNsYXNzTmFtZSA9IHBvc0ZpeGVkRWwuY2xhc3NOYW1lLnNwbGl0KFNQQUNFX0NIQVIgKyBvcHRpb25zLnBvc2l0aW9uRml4ZWRDbGFzcykuam9pbignJylcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlIFRPQyBoaWdobGlnaHRpbmcgYW5kIGNvbGxwYXNlZCBncm91cGluZ3MuXG4gICAqL1xuICBmdW5jdGlvbiB1cGRhdGVUb2MgKGhlYWRpbmdzQXJyYXkpIHtcbiAgICB2YXIgdG9wID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCB8fCBib2R5LnNjcm9sbFRvcFxuXG4gICAgLy8gQWRkIGZpeGVkIGNsYXNzIGF0IG9mZnNldDtcbiAgICBpZiAob3B0aW9ucy5wb3NpdGlvbkZpeGVkU2VsZWN0b3IpIHtcbiAgICAgIHVwZGF0ZUZpeGVkU2lkZWJhckNsYXNzKClcbiAgICB9XG5cbiAgICAvLyBHZXQgdGhlIHRvcCBtb3N0IGhlYWRpbmcgY3VycmVudGx5IHZpc2libGUgb24gdGhlIHBhZ2Ugc28gd2Uga25vdyB3aGF0IHRvIGhpZ2hsaWdodC5cbiAgICB2YXIgaGVhZGluZ3MgPSBoZWFkaW5nc0FycmF5XG4gICAgdmFyIHRvcEhlYWRlclxuICAgIC8vIFVzaW5nIHNvbWUgaW5zdGVhZCBvZiBlYWNoIHNvIHRoYXQgd2UgY2FuIGVzY2FwZSBlYXJseS5cbiAgICBpZiAoY3VycmVudGx5SGlnaGxpZ2h0aW5nICYmXG4gICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKG9wdGlvbnMudG9jU2VsZWN0b3IpICE9PSBudWxsICYmXG4gICAgICBoZWFkaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgICBzb21lLmNhbGwoaGVhZGluZ3MsIGZ1bmN0aW9uIChoZWFkaW5nLCBpKSB7XG4gICAgICAgIGlmIChoZWFkaW5nLm9mZnNldFRvcCA+IHRvcCArIG9wdGlvbnMuaGVhZGluZ3NPZmZzZXQgKyAxMCkge1xuICAgICAgICAgIC8vIERvbid0IGFsbG93IG5lZ2F0aXZlIGluZGV4IHZhbHVlLlxuICAgICAgICAgIHZhciBpbmRleCA9IChpID09PSAwKSA/IGkgOiBpIC0gMVxuICAgICAgICAgIHRvcEhlYWRlciA9IGhlYWRpbmdzW2luZGV4XVxuICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSA9PT0gaGVhZGluZ3MubGVuZ3RoIC0gMSkge1xuICAgICAgICAgIC8vIFRoaXMgYWxsb3dzIHNjcm9sbGluZyBmb3IgdGhlIGxhc3QgaGVhZGluZyBvbiB0aGUgcGFnZS5cbiAgICAgICAgICB0b3BIZWFkZXIgPSBoZWFkaW5nc1toZWFkaW5ncy5sZW5ndGggLSAxXVxuICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgIH1cbiAgICAgIH0pXG5cbiAgICAgIC8vIFJlbW92ZSB0aGUgYWN0aXZlIGNsYXNzIGZyb20gdGhlIG90aGVyIHRvY0xpbmtzLlxuICAgICAgdmFyIHRvY0xpbmtzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihvcHRpb25zLnRvY1NlbGVjdG9yKVxuICAgICAgICAucXVlcnlTZWxlY3RvckFsbCgnLicgKyBvcHRpb25zLmxpbmtDbGFzcylcbiAgICAgIGZvckVhY2guY2FsbCh0b2NMaW5rcywgZnVuY3Rpb24gKHRvY0xpbmspIHtcbiAgICAgICAgdG9jTGluay5jbGFzc05hbWUgPSB0b2NMaW5rLmNsYXNzTmFtZS5zcGxpdChTUEFDRV9DSEFSICsgb3B0aW9ucy5hY3RpdmVMaW5rQ2xhc3MpLmpvaW4oJycpXG4gICAgICB9KVxuXG4gICAgICAvLyBBZGQgdGhlIGFjdGl2ZSBjbGFzcyB0byB0aGUgYWN0aXZlIHRvY0xpbmsuXG4gICAgICB2YXIgYWN0aXZlVG9jTGluayA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iob3B0aW9ucy50b2NTZWxlY3RvcilcbiAgICAgICAgLnF1ZXJ5U2VsZWN0b3IoJy4nICsgb3B0aW9ucy5saW5rQ2xhc3MgK1xuICAgICAgICAgICcubm9kZS1uYW1lLS0nICsgdG9wSGVhZGVyLm5vZGVOYW1lICtcbiAgICAgICAgICAnW2hyZWY9XCIjJyArIHRvcEhlYWRlci5pZCArICdcIl0nKVxuICAgICAgYWN0aXZlVG9jTGluay5jbGFzc05hbWUgKz0gU1BBQ0VfQ0hBUiArIG9wdGlvbnMuYWN0aXZlTGlua0NsYXNzXG5cbiAgICAgIHZhciB0b2NMaXN0cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Iob3B0aW9ucy50b2NTZWxlY3RvcilcbiAgICAgICAgLnF1ZXJ5U2VsZWN0b3JBbGwoJy4nICsgb3B0aW9ucy5saXN0Q2xhc3MgKyAnLicgKyBvcHRpb25zLmNvbGxhcHNpYmxlQ2xhc3MpXG5cbiAgICAgIC8vIENvbGxhcHNlIHRoZSBvdGhlciBjb2xsYXBzaWJsZSBsaXN0cy5cbiAgICAgIGZvckVhY2guY2FsbCh0b2NMaXN0cywgZnVuY3Rpb24gKGxpc3QpIHtcbiAgICAgICAgdmFyIGNvbGxhcHNlZENsYXNzID0gU1BBQ0VfQ0hBUiArIG9wdGlvbnMuaXNDb2xsYXBzZWRDbGFzc1xuICAgICAgICBpZiAobGlzdC5jbGFzc05hbWUuaW5kZXhPZihjb2xsYXBzZWRDbGFzcykgPT09IC0xKSB7XG4gICAgICAgICAgbGlzdC5jbGFzc05hbWUgKz0gU1BBQ0VfQ0hBUiArIG9wdGlvbnMuaXNDb2xsYXBzZWRDbGFzc1xuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICAvLyBFeHBhbmQgdGhlIGFjdGl2ZSBsaW5rJ3MgY29sbGFwc2libGUgbGlzdCBhbmQgaXRzIHNpYmxpbmcgaWYgYXBwbGljYWJsZS5cbiAgICAgIGlmIChhY3RpdmVUb2NMaW5rLm5leHRTaWJsaW5nKSB7XG4gICAgICAgIGFjdGl2ZVRvY0xpbmsubmV4dFNpYmxpbmcuY2xhc3NOYW1lID0gYWN0aXZlVG9jTGluay5uZXh0U2libGluZy5jbGFzc05hbWUuc3BsaXQoU1BBQ0VfQ0hBUiArIG9wdGlvbnMuaXNDb2xsYXBzZWRDbGFzcykuam9pbignJylcbiAgICAgIH1cbiAgICAgIHJlbW92ZUNvbGxhcHNlZEZyb21QYXJlbnRzKGFjdGl2ZVRvY0xpbmsucGFyZW50Tm9kZS5wYXJlbnROb2RlKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgY29sbHBhc2VkIGNsYXNzIGZyb20gcGFyZW50IGVsZW1lbnRzLlxuICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbGVtZW50XG4gICAqIEByZXR1cm4ge0hUTUxFbGVtZW50fVxuICAgKi9cbiAgZnVuY3Rpb24gcmVtb3ZlQ29sbGFwc2VkRnJvbVBhcmVudHMgKGVsZW1lbnQpIHtcbiAgICBpZiAoZWxlbWVudC5jbGFzc05hbWUuaW5kZXhPZihvcHRpb25zLmNvbGxhcHNpYmxlQ2xhc3MpICE9PSAtMSkge1xuICAgICAgZWxlbWVudC5jbGFzc05hbWUgPSBlbGVtZW50LmNsYXNzTmFtZS5zcGxpdChTUEFDRV9DSEFSICsgb3B0aW9ucy5pc0NvbGxhcHNlZENsYXNzKS5qb2luKCcnKVxuICAgICAgcmV0dXJuIHJlbW92ZUNvbGxhcHNlZEZyb21QYXJlbnRzKGVsZW1lbnQucGFyZW50Tm9kZS5wYXJlbnROb2RlKVxuICAgIH1cbiAgICByZXR1cm4gZWxlbWVudFxuICB9XG5cbiAgLyoqXG4gICAqIERpc2FibGUgVE9DIEFuaW1hdGlvbiB3aGVuIGEgbGluayBpcyBjbGlja2VkLlxuICAgKiBAcGFyYW0ge0V2ZW50fSBldmVudFxuICAgKi9cbiAgZnVuY3Rpb24gZGlzYWJsZVRvY0FuaW1hdGlvbiAoZXZlbnQpIHtcbiAgICB2YXIgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IHx8IGV2ZW50LnNyY0VsZW1lbnRcbiAgICBpZiAodHlwZW9mIHRhcmdldC5jbGFzc05hbWUgIT09ICdzdHJpbmcnIHx8IHRhcmdldC5jbGFzc05hbWUuaW5kZXhPZihvcHRpb25zLmxpbmtDbGFzcykgPT09IC0xKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgLy8gQmluZCB0byB0b2NMaW5rIGNsaWNrcyB0byB0ZW1wb3JhcmlseSBkaXNhYmxlIGhpZ2hsaWdodGluZ1xuICAgIC8vIHdoaWxlIHNtb290aFNjcm9sbCBpcyBhbmltYXRpbmcuXG4gICAgY3VycmVudGx5SGlnaGxpZ2h0aW5nID0gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGUgVE9DIEFuaW1hdGlvbi5cbiAgICovXG4gIGZ1bmN0aW9uIGVuYWJsZVRvY0FuaW1hdGlvbiAoKSB7XG4gICAgY3VycmVudGx5SGlnaGxpZ2h0aW5nID0gdHJ1ZVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBlbmFibGVUb2NBbmltYXRpb246IGVuYWJsZVRvY0FuaW1hdGlvbixcbiAgICBkaXNhYmxlVG9jQW5pbWF0aW9uOiBkaXNhYmxlVG9jQW5pbWF0aW9uLFxuICAgIHJlbmRlcjogcmVuZGVyLFxuICAgIHVwZGF0ZVRvYzogdXBkYXRlVG9jXG4gIH1cbn1cblxuXG5cbi8vLy8vLy8vLy8vLy8vLy8vL1xuLy8gV0VCUEFDSyBGT09URVJcbi8vIC4vc3JjL2pzL2J1aWxkLWh0bWwuanNcbi8vIG1vZHVsZSBpZCA9IDJcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOyIsInNvdXJjZVJvb3QiOiIifQ=="); - -/***/ }), -/* 3 */ -/* unknown exports provided */ -/* all exports used */ -/*!***********************************!*\ - !*** ./src/js/default-options.js ***! - \***********************************/ -/***/ (function(module, exports) { - -eval("module.exports = {\n // Where to render the table of contents.\n tocSelector: '.js-toc',\n // Where to grab the headings to build the table of contents.\n contentSelector: '.js-toc-content',\n // Which headings to grab inside of the contentSelector element.\n headingSelector: 'h1, h2, h3',\n // Headings that match the ignoreSelector will be skipped.\n ignoreSelector: '.js-toc-ignore',\n // Main class to add to links.\n linkClass: 'toc-link',\n // Extra classes to add to links.\n extraLinkClasses: '',\n // Class to add to active links,\n // the link corresponding to the top most heading on the page.\n activeLinkClass: 'is-active-link',\n // Main class to add to lists.\n listClass: 'toc-list',\n // Extra classes to add to lists.\n extraListClasses: '',\n // Class that gets added when a list should be collapsed.\n isCollapsedClass: 'is-collapsed',\n // Class that gets added when a list should be able\n // to be collapsed but isn't necessarily collpased.\n collapsibleClass: 'is-collapsible',\n // Class to add to list items.\n listItemClass: 'toc-list-item',\n // How many heading levels should not be collpased.\n // For example, number 6 will show everything since\n // there are only 6 heading levels and number 0 will collpase them all.\n // The sections that are hidden will open\n // and close as you scroll to headings within them.\n collapseDepth: 0,\n // Smooth scrolling enabled.\n smoothScroll: true,\n // Smooth scroll duration.\n smoothScrollDuration: 420,\n // Callback for scroll end (requires: smoothScroll).\n scrollEndCallback: function (e) {},\n // Headings offset between the headings and the top of the document.\n headingsOffset: 0,\n // Timeout between events firing to make sure it's\n // not too rapid (for performance reasons).\n throttleTimeout: 50,\n // Element to add the positionFixedClass to.\n positionFixedSelector: null,\n // Fixed position class to add to make sidebar fixed after scrolling\n // down past the fixedSidebarOffset.\n positionFixedClass: 'is-position-fixed',\n // fixedSidebarOffset can be any number but by default is set\n // to auto which sets the fixedSidebarOffset to the sidebar\n // element's offsetTop from the top of the document on init.\n fixedSidebarOffset: 'auto',\n // includeHtml can be set to true to include the HTML markup from the\n // heading node instead of just including the textContent.\n includeHtml: false\n}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMy5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3NyYy9qcy9kZWZhdWx0LW9wdGlvbnMuanM/MTg1MSJdLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuZXhwb3J0cyA9IHtcbiAgLy8gV2hlcmUgdG8gcmVuZGVyIHRoZSB0YWJsZSBvZiBjb250ZW50cy5cbiAgdG9jU2VsZWN0b3I6ICcuanMtdG9jJyxcbiAgLy8gV2hlcmUgdG8gZ3JhYiB0aGUgaGVhZGluZ3MgdG8gYnVpbGQgdGhlIHRhYmxlIG9mIGNvbnRlbnRzLlxuICBjb250ZW50U2VsZWN0b3I6ICcuanMtdG9jLWNvbnRlbnQnLFxuICAvLyBXaGljaCBoZWFkaW5ncyB0byBncmFiIGluc2lkZSBvZiB0aGUgY29udGVudFNlbGVjdG9yIGVsZW1lbnQuXG4gIGhlYWRpbmdTZWxlY3RvcjogJ2gxLCBoMiwgaDMnLFxuICAvLyBIZWFkaW5ncyB0aGF0IG1hdGNoIHRoZSBpZ25vcmVTZWxlY3RvciB3aWxsIGJlIHNraXBwZWQuXG4gIGlnbm9yZVNlbGVjdG9yOiAnLmpzLXRvYy1pZ25vcmUnLFxuICAvLyBNYWluIGNsYXNzIHRvIGFkZCB0byBsaW5rcy5cbiAgbGlua0NsYXNzOiAndG9jLWxpbmsnLFxuICAvLyBFeHRyYSBjbGFzc2VzIHRvIGFkZCB0byBsaW5rcy5cbiAgZXh0cmFMaW5rQ2xhc3NlczogJycsXG4gIC8vIENsYXNzIHRvIGFkZCB0byBhY3RpdmUgbGlua3MsXG4gIC8vIHRoZSBsaW5rIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHRvcCBtb3N0IGhlYWRpbmcgb24gdGhlIHBhZ2UuXG4gIGFjdGl2ZUxpbmtDbGFzczogJ2lzLWFjdGl2ZS1saW5rJyxcbiAgLy8gTWFpbiBjbGFzcyB0byBhZGQgdG8gbGlzdHMuXG4gIGxpc3RDbGFzczogJ3RvYy1saXN0JyxcbiAgLy8gRXh0cmEgY2xhc3NlcyB0byBhZGQgdG8gbGlzdHMuXG4gIGV4dHJhTGlzdENsYXNzZXM6ICcnLFxuICAvLyBDbGFzcyB0aGF0IGdldHMgYWRkZWQgd2hlbiBhIGxpc3Qgc2hvdWxkIGJlIGNvbGxhcHNlZC5cbiAgaXNDb2xsYXBzZWRDbGFzczogJ2lzLWNvbGxhcHNlZCcsXG4gIC8vIENsYXNzIHRoYXQgZ2V0cyBhZGRlZCB3aGVuIGEgbGlzdCBzaG91bGQgYmUgYWJsZVxuICAvLyB0byBiZSBjb2xsYXBzZWQgYnV0IGlzbid0IG5lY2Vzc2FyaWx5IGNvbGxwYXNlZC5cbiAgY29sbGFwc2libGVDbGFzczogJ2lzLWNvbGxhcHNpYmxlJyxcbiAgLy8gQ2xhc3MgdG8gYWRkIHRvIGxpc3QgaXRlbXMuXG4gIGxpc3RJdGVtQ2xhc3M6ICd0b2MtbGlzdC1pdGVtJyxcbiAgLy8gSG93IG1hbnkgaGVhZGluZyBsZXZlbHMgc2hvdWxkIG5vdCBiZSBjb2xscGFzZWQuXG4gIC8vIEZvciBleGFtcGxlLCBudW1iZXIgNiB3aWxsIHNob3cgZXZlcnl0aGluZyBzaW5jZVxuICAvLyB0aGVyZSBhcmUgb25seSA2IGhlYWRpbmcgbGV2ZWxzIGFuZCBudW1iZXIgMCB3aWxsIGNvbGxwYXNlIHRoZW0gYWxsLlxuICAvLyBUaGUgc2VjdGlvbnMgdGhhdCBhcmUgaGlkZGVuIHdpbGwgb3BlblxuICAvLyBhbmQgY2xvc2UgYXMgeW91IHNjcm9sbCB0byBoZWFkaW5ncyB3aXRoaW4gdGhlbS5cbiAgY29sbGFwc2VEZXB0aDogMCxcbiAgLy8gU21vb3RoIHNjcm9sbGluZyBlbmFibGVkLlxuICBzbW9vdGhTY3JvbGw6IHRydWUsXG4gIC8vIFNtb290aCBzY3JvbGwgZHVyYXRpb24uXG4gIHNtb290aFNjcm9sbER1cmF0aW9uOiA0MjAsXG4gIC8vIENhbGxiYWNrIGZvciBzY3JvbGwgZW5kIChyZXF1aXJlczogc21vb3RoU2Nyb2xsKS5cbiAgc2Nyb2xsRW5kQ2FsbGJhY2s6IGZ1bmN0aW9uIChlKSB7fSxcbiAgLy8gSGVhZGluZ3Mgb2Zmc2V0IGJldHdlZW4gdGhlIGhlYWRpbmdzIGFuZCB0aGUgdG9wIG9mIHRoZSBkb2N1bWVudC5cbiAgaGVhZGluZ3NPZmZzZXQ6IDAsXG4gIC8vIFRpbWVvdXQgYmV0d2VlbiBldmVudHMgZmlyaW5nIHRvIG1ha2Ugc3VyZSBpdCdzXG4gIC8vIG5vdCB0b28gcmFwaWQgKGZvciBwZXJmb3JtYW5jZSByZWFzb25zKS5cbiAgdGhyb3R0bGVUaW1lb3V0OiA1MCxcbiAgLy8gRWxlbWVudCB0byBhZGQgdGhlIHBvc2l0aW9uRml4ZWRDbGFzcyB0by5cbiAgcG9zaXRpb25GaXhlZFNlbGVjdG9yOiBudWxsLFxuICAvLyBGaXhlZCBwb3NpdGlvbiBjbGFzcyB0byBhZGQgdG8gbWFrZSBzaWRlYmFyIGZpeGVkIGFmdGVyIHNjcm9sbGluZ1xuICAvLyBkb3duIHBhc3QgdGhlIGZpeGVkU2lkZWJhck9mZnNldC5cbiAgcG9zaXRpb25GaXhlZENsYXNzOiAnaXMtcG9zaXRpb24tZml4ZWQnLFxuICAvLyBmaXhlZFNpZGViYXJPZmZzZXQgY2FuIGJlIGFueSBudW1iZXIgYnV0IGJ5IGRlZmF1bHQgaXMgc2V0XG4gIC8vIHRvIGF1dG8gd2hpY2ggc2V0cyB0aGUgZml4ZWRTaWRlYmFyT2Zmc2V0IHRvIHRoZSBzaWRlYmFyXG4gIC8vIGVsZW1lbnQncyBvZmZzZXRUb3AgZnJvbSB0aGUgdG9wIG9mIHRoZSBkb2N1bWVudCBvbiBpbml0LlxuICBmaXhlZFNpZGViYXJPZmZzZXQ6ICdhdXRvJyxcbiAgLy8gaW5jbHVkZUh0bWwgY2FuIGJlIHNldCB0byB0cnVlIHRvIGluY2x1ZGUgdGhlIEhUTUwgbWFya3VwIGZyb20gdGhlXG4gIC8vIGhlYWRpbmcgbm9kZSBpbnN0ZWFkIG9mIGp1c3QgaW5jbHVkaW5nIHRoZSB0ZXh0Q29udGVudC5cbiAgaW5jbHVkZUh0bWw6IGZhbHNlXG59XG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL3NyYy9qcy9kZWZhdWx0LW9wdGlvbnMuanNcbi8vIG1vZHVsZSBpZCA9IDNcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Iiwic291cmNlUm9vdCI6IiJ9"); - -/***/ }), -/* 4 */ -/* unknown exports provided */ -/* all exports used */ -/*!*********************************!*\ - !*** ./src/js/parse-content.js ***! - \*********************************/ -/***/ (function(module, exports) { - -eval("/**\n * This file is responsible for parsing the content from the DOM and making\n * sure data is nested properly.\n *\n * @author Tim Scanlin\n */\n\nmodule.exports = function parseContent (options) {\n var reduce = [].reduce\n\n /**\n * Get the last item in an array and return a reference to it.\n * @param {Array} array\n * @return {Object}\n */\n function getLastItem (array) {\n return array[array.length - 1]\n }\n\n /**\n * Get heading level for a heading dom node.\n * @param {HTMLElement} heading\n * @return {Number}\n */\n function getHeadingLevel (heading) {\n return +heading.nodeName.split('H').join('')\n }\n\n /**\n * Get important properties from a heading element and store in a plain object.\n * @param {HTMLElement} heading\n * @return {Object}\n */\n function getHeadingObject (heading) {\n var obj = {\n id: heading.id,\n children: [],\n nodeName: heading.nodeName,\n headingLevel: getHeadingLevel(heading),\n textContent: heading.textContent.trim()\n }\n\n if (options.includeHtml) {\n obj.childNodes = heading.childNodes\n }\n\n return obj\n }\n\n /**\n * Add a node to the nested array.\n * @param {Object} node\n * @param {Array} nest\n * @return {Array}\n */\n function addNode (node, nest) {\n var obj = getHeadingObject(node)\n var level = getHeadingLevel(node)\n var array = nest\n var lastItem = getLastItem(array)\n var lastItemLevel = lastItem\n ? lastItem.headingLevel\n : 0\n var counter = level - lastItemLevel\n\n while (counter > 0) {\n lastItem = getLastItem(array)\n if (lastItem && lastItem.children !== undefined) {\n array = lastItem.children\n }\n counter--\n }\n\n if (level >= options.collapseDepth) {\n obj.isCollapsed = true\n }\n\n array.push(obj)\n return array\n }\n\n /**\n * Select headings in content area, exclude any selector in options.ignoreSelector\n * @param {String} contentSelector\n * @param {Array} headingSelector\n * @return {Array}\n */\n function selectHeadings (contentSelector, headingSelector) {\n var selectors = headingSelector\n if (options.ignoreSelector) {\n selectors = headingSelector.split(',')\n .map(function mapSelectors (selector) {\n return selector.trim() + ':not(' + options.ignoreSelector + ')'\n })\n }\n try {\n return document.querySelector(contentSelector)\n .querySelectorAll(selectors)\n } catch (e) {\n console.warn('Element not found: ' + contentSelector); // eslint-disable-line\n return null\n }\n }\n\n /**\n * Nest headings array into nested arrays with 'children' property.\n * @param {Array} headingsArray\n * @return {Object}\n */\n function nestHeadingsArray (headingsArray) {\n return reduce.call(headingsArray, function reducer (prev, curr) {\n var currentHeading = getHeadingObject(curr)\n\n addNode(currentHeading, prev.nest)\n return prev\n }, {\n nest: []\n })\n }\n\n return {\n nestHeadingsArray: nestHeadingsArray,\n selectHeadings: selectHeadings\n }\n}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3NyYy9qcy9wYXJzZS1jb250ZW50LmpzPzg3ZjAiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGNvbnRlbnQgZnJvbSB0aGUgRE9NIGFuZCBtYWtpbmdcbiAqIHN1cmUgZGF0YSBpcyBuZXN0ZWQgcHJvcGVybHkuXG4gKlxuICogQGF1dGhvciBUaW0gU2NhbmxpblxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFyc2VDb250ZW50IChvcHRpb25zKSB7XG4gIHZhciByZWR1Y2UgPSBbXS5yZWR1Y2VcblxuICAvKipcbiAgICogR2V0IHRoZSBsYXN0IGl0ZW0gaW4gYW4gYXJyYXkgYW5kIHJldHVybiBhIHJlZmVyZW5jZSB0byBpdC5cbiAgICogQHBhcmFtIHtBcnJheX0gYXJyYXlcbiAgICogQHJldHVybiB7T2JqZWN0fVxuICAgKi9cbiAgZnVuY3Rpb24gZ2V0TGFzdEl0ZW0gKGFycmF5KSB7XG4gICAgcmV0dXJuIGFycmF5W2FycmF5Lmxlbmd0aCAtIDFdXG4gIH1cblxuICAvKipcbiAgICogR2V0IGhlYWRpbmcgbGV2ZWwgZm9yIGEgaGVhZGluZyBkb20gbm9kZS5cbiAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gaGVhZGluZ1xuICAgKiBAcmV0dXJuIHtOdW1iZXJ9XG4gICAqL1xuICBmdW5jdGlvbiBnZXRIZWFkaW5nTGV2ZWwgKGhlYWRpbmcpIHtcbiAgICByZXR1cm4gK2hlYWRpbmcubm9kZU5hbWUuc3BsaXQoJ0gnKS5qb2luKCcnKVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBpbXBvcnRhbnQgcHJvcGVydGllcyBmcm9tIGEgaGVhZGluZyBlbGVtZW50IGFuZCBzdG9yZSBpbiBhIHBsYWluIG9iamVjdC5cbiAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gaGVhZGluZ1xuICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAqL1xuICBmdW5jdGlvbiBnZXRIZWFkaW5nT2JqZWN0IChoZWFkaW5nKSB7XG4gICAgdmFyIG9iaiA9IHtcbiAgICAgIGlkOiBoZWFkaW5nLmlkLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgICAgbm9kZU5hbWU6IGhlYWRpbmcubm9kZU5hbWUsXG4gICAgICBoZWFkaW5nTGV2ZWw6IGdldEhlYWRpbmdMZXZlbChoZWFkaW5nKSxcbiAgICAgIHRleHRDb250ZW50OiBoZWFkaW5nLnRleHRDb250ZW50LnRyaW0oKVxuICAgIH1cblxuICAgIGlmIChvcHRpb25zLmluY2x1ZGVIdG1sKSB7XG4gICAgICBvYmouY2hpbGROb2RlcyA9IGhlYWRpbmcuY2hpbGROb2Rlc1xuICAgIH1cblxuICAgIHJldHVybiBvYmpcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBub2RlIHRvIHRoZSBuZXN0ZWQgYXJyYXkuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG4gICAqIEBwYXJhbSB7QXJyYXl9IG5lc3RcbiAgICogQHJldHVybiB7QXJyYXl9XG4gICAqL1xuICBmdW5jdGlvbiBhZGROb2RlIChub2RlLCBuZXN0KSB7XG4gICAgdmFyIG9iaiA9IGdldEhlYWRpbmdPYmplY3Qobm9kZSlcbiAgICB2YXIgbGV2ZWwgPSBnZXRIZWFkaW5nTGV2ZWwobm9kZSlcbiAgICB2YXIgYXJyYXkgPSBuZXN0XG4gICAgdmFyIGxhc3RJdGVtID0gZ2V0TGFzdEl0ZW0oYXJyYXkpXG4gICAgdmFyIGxhc3RJdGVtTGV2ZWwgPSBsYXN0SXRlbVxuICAgICAgPyBsYXN0SXRlbS5oZWFkaW5nTGV2ZWxcbiAgICAgIDogMFxuICAgIHZhciBjb3VudGVyID0gbGV2ZWwgLSBsYXN0SXRlbUxldmVsXG5cbiAgICB3aGlsZSAoY291bnRlciA+IDApIHtcbiAgICAgIGxhc3RJdGVtID0gZ2V0TGFzdEl0ZW0oYXJyYXkpXG4gICAgICBpZiAobGFzdEl0ZW0gJiYgbGFzdEl0ZW0uY2hpbGRyZW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhcnJheSA9IGxhc3RJdGVtLmNoaWxkcmVuXG4gICAgICB9XG4gICAgICBjb3VudGVyLS1cbiAgICB9XG5cbiAgICBpZiAobGV2ZWwgPj0gb3B0aW9ucy5jb2xsYXBzZURlcHRoKSB7XG4gICAgICBvYmouaXNDb2xsYXBzZWQgPSB0cnVlXG4gICAgfVxuXG4gICAgYXJyYXkucHVzaChvYmopXG4gICAgcmV0dXJuIGFycmF5XG4gIH1cblxuICAvKipcbiAgICogU2VsZWN0IGhlYWRpbmdzIGluIGNvbnRlbnQgYXJlYSwgZXhjbHVkZSBhbnkgc2VsZWN0b3IgaW4gb3B0aW9ucy5pZ25vcmVTZWxlY3RvclxuICAgKiBAcGFyYW0ge1N0cmluZ30gY29udGVudFNlbGVjdG9yXG4gICAqIEBwYXJhbSB7QXJyYXl9IGhlYWRpbmdTZWxlY3RvclxuICAgKiBAcmV0dXJuIHtBcnJheX1cbiAgICovXG4gIGZ1bmN0aW9uIHNlbGVjdEhlYWRpbmdzIChjb250ZW50U2VsZWN0b3IsIGhlYWRpbmdTZWxlY3Rvcikge1xuICAgIHZhciBzZWxlY3RvcnMgPSBoZWFkaW5nU2VsZWN0b3JcbiAgICBpZiAob3B0aW9ucy5pZ25vcmVTZWxlY3Rvcikge1xuICAgICAgc2VsZWN0b3JzID0gaGVhZGluZ1NlbGVjdG9yLnNwbGl0KCcsJylcbiAgICAgICAgLm1hcChmdW5jdGlvbiBtYXBTZWxlY3RvcnMgKHNlbGVjdG9yKSB7XG4gICAgICAgICAgcmV0dXJuIHNlbGVjdG9yLnRyaW0oKSArICc6bm90KCcgKyBvcHRpb25zLmlnbm9yZVNlbGVjdG9yICsgJyknXG4gICAgICAgIH0pXG4gICAgfVxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihjb250ZW50U2VsZWN0b3IpXG4gICAgICAgIC5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9ycylcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ0VsZW1lbnQgbm90IGZvdW5kOiAnICsgY29udGVudFNlbGVjdG9yKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTmVzdCBoZWFkaW5ncyBhcnJheSBpbnRvIG5lc3RlZCBhcnJheXMgd2l0aCAnY2hpbGRyZW4nIHByb3BlcnR5LlxuICAgKiBAcGFyYW0ge0FycmF5fSBoZWFkaW5nc0FycmF5XG4gICAqIEByZXR1cm4ge09iamVjdH1cbiAgICovXG4gIGZ1bmN0aW9uIG5lc3RIZWFkaW5nc0FycmF5IChoZWFkaW5nc0FycmF5KSB7XG4gICAgcmV0dXJuIHJlZHVjZS5jYWxsKGhlYWRpbmdzQXJyYXksIGZ1bmN0aW9uIHJlZHVjZXIgKHByZXYsIGN1cnIpIHtcbiAgICAgIHZhciBjdXJyZW50SGVhZGluZyA9IGdldEhlYWRpbmdPYmplY3QoY3VycilcblxuICAgICAgYWRkTm9kZShjdXJyZW50SGVhZGluZywgcHJldi5uZXN0KVxuICAgICAgcmV0dXJuIHByZXZcbiAgICB9LCB7XG4gICAgICBuZXN0OiBbXVxuICAgIH0pXG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5lc3RIZWFkaW5nc0FycmF5OiBuZXN0SGVhZGluZ3NBcnJheSxcbiAgICBzZWxlY3RIZWFkaW5nczogc2VsZWN0SGVhZGluZ3NcbiAgfVxufVxuXG5cblxuLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBXRUJQQUNLIEZPT1RFUlxuLy8gLi9zcmMvanMvcGFyc2UtY29udGVudC5qc1xuLy8gbW9kdWxlIGlkID0gNFxuLy8gbW9kdWxlIGNodW5rcyA9IDAiXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Iiwic291cmNlUm9vdCI6IiJ9"); - -/***/ }), -/* 5 */ -/* unknown exports provided */ -/* all exports used */ -/*!*************************!*\ - !*** ./src/js/index.js ***! - \*************************/ -/***/ (function(module, exports, __webpack_require__) { - -eval("/* WEBPACK VAR INJECTION */(function(global) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**\n * Tocbot\n * Tocbot creates a toble of contents based on HTML headings on a page,\n * this allows users to easily jump to different sections of the document.\n * Tocbot was inspired by tocify (https://gregfranko.com/jquery.tocify.js/).\n * The main differences are that it works natively without any need for jquery or jquery UI).\n *\n * @author Tim Scanlin\n */\n\n/* globals define */\n\n(function (root, factory) {\n if (true) {\n !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory(root)),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))\n } else if (typeof exports === 'object') {\n module.exports = factory(root)\n } else {\n root.tocbot = factory(root)\n }\n})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {\n 'use strict'\n\n // Default options.\n var defaultOptions = __webpack_require__(/*! ./default-options.js */ 3)\n // Object to store current options.\n var options = {}\n // Object for public APIs.\n var tocbot = {}\n\n var BuildHtml = __webpack_require__(/*! ./build-html.js */ 2)\n var ParseContent = __webpack_require__(/*! ./parse-content.js */ 4)\n // Keep these variables at top scope once options are passed in.\n var buildHtml\n var parseContent\n\n // Just return if its not a browser.\n if (typeof window === 'undefined') {\n return\n }\n var supports = !!root.document.querySelector && !!root.addEventListener // Feature test\n var headingsArray\n\n // From: https://github.com/Raynos/xtend\n var hasOwnProperty = Object.prototype.hasOwnProperty\n function extend () {\n var target = {}\n for (var i = 0; i < arguments.length; i++) {\n var source = arguments[i]\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key]\n }\n }\n }\n return target\n }\n\n // From: https://remysharp.com/2010/07/21/throttling-function-calls\n function throttle (fn, threshhold, scope) {\n threshhold || (threshhold = 250)\n var last\n var deferTimer\n return function () {\n var context = scope || this\n var now = +new Date()\n var args = arguments\n if (last && now < last + threshhold) {\n // hold on to it\n clearTimeout(deferTimer)\n deferTimer = setTimeout(function () {\n last = now\n fn.apply(context, args)\n }, threshhold)\n } else {\n last = now\n fn.apply(context, args)\n }\n }\n }\n\n /**\n * Destroy tocbot.\n */\n tocbot.destroy = function () {\n // Clear HTML.\n try {\n document.querySelector(options.tocSelector).innerHTML = ''\n } catch (e) {\n console.warn('Element not found: ' + options.tocSelector); // eslint-disable-line\n }\n\n // Remove event listeners.\n document.removeEventListener('scroll', this._scrollListener, false)\n document.removeEventListener('resize', this._scrollListener, false)\n if (buildHtml) {\n document.removeEventListener('click', this._clickListener, false)\n }\n }\n\n /**\n * Initialize tocbot.\n * @param {object} customOptions\n */\n tocbot.init = function (customOptions) {\n // feature test\n if (!supports) {\n return\n }\n\n // Merge defaults with user options.\n // Set to options variable at the top.\n options = extend(defaultOptions, customOptions || {})\n this.options = options\n this.state = {}\n\n // Init smooth scroll if enabled (default).\n if (options.smoothScroll) {\n tocbot.zenscroll = __webpack_require__(/*! zenscroll */ 1)\n tocbot.zenscroll.setup(options.smoothScrollDuration)\n }\n\n // Pass options to these modules.\n buildHtml = BuildHtml(options)\n parseContent = ParseContent(options)\n\n // For testing purposes.\n this._buildHtml = buildHtml\n this._parseContent = parseContent\n\n // Destroy it if it exists first.\n tocbot.destroy()\n\n // Get headings array.\n headingsArray = parseContent.selectHeadings(options.contentSelector, options.headingSelector)\n // Return if no headings are found.\n if (headingsArray === null) {\n return\n }\n\n // Build nested headings array.\n var nestedHeadingsObj = parseContent.nestHeadingsArray(headingsArray)\n var nestedHeadings = nestedHeadingsObj.nest\n\n // Render.\n buildHtml.render(options.tocSelector, nestedHeadings)\n\n // Update Sidebar and bind listeners.\n this._scrollListener = throttle(function (e) {\n buildHtml.updateToc(headingsArray)\n var isTop = e && e.target && e.target.scrollingElement && e.target.scrollingElement.scrollTop === 0\n if ((e && e.eventPhase === 0) || isTop) {\n buildHtml.enableTocAnimation()\n buildHtml.updateToc(headingsArray)\n if (options.scrollEndCallback) {\n options.scrollEndCallback(e)\n }\n }\n }, options.throttleTimeout)\n this._scrollListener()\n document.addEventListener('scroll', this._scrollListener, false)\n document.addEventListener('resize', this._scrollListener, false)\n\n // Bind click listeners to disable animation.\n this._clickListener = throttle(function (event) {\n if (options.smoothScroll) {\n buildHtml.disableTocAnimation(event)\n }\n buildHtml.updateToc(headingsArray)\n }, options.throttleTimeout)\n document.addEventListener('click', this._clickListener, false)\n\n return this\n }\n\n /**\n * Refresh tocbot.\n */\n tocbot.refresh = function (customOptions) {\n tocbot.destroy()\n tocbot.init(customOptions || this.options)\n }\n\n // Make tocbot available globally.\n root.tocbot = tocbot\n\n return tocbot\n})\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ./../../~/webpack/buildin/global.js */ 0)))//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL3NyYy9qcy9pbmRleC5qcz9iYzY2Il0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVG9jYm90XG4gKiBUb2Nib3QgY3JlYXRlcyBhIHRvYmxlIG9mIGNvbnRlbnRzIGJhc2VkIG9uIEhUTUwgaGVhZGluZ3Mgb24gYSBwYWdlLFxuICogdGhpcyBhbGxvd3MgdXNlcnMgdG8gZWFzaWx5IGp1bXAgdG8gZGlmZmVyZW50IHNlY3Rpb25zIG9mIHRoZSBkb2N1bWVudC5cbiAqIFRvY2JvdCB3YXMgaW5zcGlyZWQgYnkgdG9jaWZ5IChodHRwOi8vZ3JlZ2ZyYW5rby5jb20vanF1ZXJ5LnRvY2lmeS5qcy8pLlxuICogVGhlIG1haW4gZGlmZmVyZW5jZXMgYXJlIHRoYXQgaXQgd29ya3MgbmF0aXZlbHkgd2l0aG91dCBhbnkgbmVlZCBmb3IganF1ZXJ5IG9yIGpxdWVyeSBVSSkuXG4gKlxuICogQGF1dGhvciBUaW0gU2NhbmxpblxuICovXG5cbi8qIGdsb2JhbHMgZGVmaW5lICovXG5cbihmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuICBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgZGVmaW5lKFtdLCBmYWN0b3J5KHJvb3QpKVxuICB9IGVsc2UgaWYgKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0Jykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyb290KVxuICB9IGVsc2Uge1xuICAgIHJvb3QudG9jYm90ID0gZmFjdG9yeShyb290KVxuICB9XG59KSh0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6IHRoaXMud2luZG93IHx8IHRoaXMuZ2xvYmFsLCBmdW5jdGlvbiAocm9vdCkge1xuICAndXNlIHN0cmljdCdcblxuICAvLyBEZWZhdWx0IG9wdGlvbnMuXG4gIHZhciBkZWZhdWx0T3B0aW9ucyA9IHJlcXVpcmUoJy4vZGVmYXVsdC1vcHRpb25zLmpzJylcbiAgLy8gT2JqZWN0IHRvIHN0b3JlIGN1cnJlbnQgb3B0aW9ucy5cbiAgdmFyIG9wdGlvbnMgPSB7fVxuICAvLyBPYmplY3QgZm9yIHB1YmxpYyBBUElzLlxuICB2YXIgdG9jYm90ID0ge31cblxuICB2YXIgQnVpbGRIdG1sID0gcmVxdWlyZSgnLi9idWlsZC1odG1sLmpzJylcbiAgdmFyIFBhcnNlQ29udGVudCA9IHJlcXVpcmUoJy4vcGFyc2UtY29udGVudC5qcycpXG4gIC8vIEtlZXAgdGhlc2UgdmFyaWFibGVzIGF0IHRvcCBzY29wZSBvbmNlIG9wdGlvbnMgYXJlIHBhc3NlZCBpbi5cbiAgdmFyIGJ1aWxkSHRtbFxuICB2YXIgcGFyc2VDb250ZW50XG5cbiAgLy8gSnVzdCByZXR1cm4gaWYgaXRzIG5vdCBhIGJyb3dzZXIuXG4gIGlmICh0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJykge1xuICAgIHJldHVyblxuICB9XG4gIHZhciBzdXBwb3J0cyA9ICEhcm9vdC5kb2N1bWVudC5xdWVyeVNlbGVjdG9yICYmICEhcm9vdC5hZGRFdmVudExpc3RlbmVyIC8vIEZlYXR1cmUgdGVzdFxuICB2YXIgaGVhZGluZ3NBcnJheVxuXG4gIC8vIEZyb206IGh0dHBzOi8vZ2l0aHViLmNvbS9SYXlub3MveHRlbmRcbiAgdmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eVxuICBmdW5jdGlvbiBleHRlbmQgKCkge1xuICAgIHZhciB0YXJnZXQgPSB7fVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgc291cmNlID0gYXJndW1lbnRzW2ldXG4gICAgICBmb3IgKHZhciBrZXkgaW4gc291cmNlKSB7XG4gICAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKHNvdXJjZSwga2V5KSkge1xuICAgICAgICAgIHRhcmdldFtrZXldID0gc291cmNlW2tleV1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGFyZ2V0XG4gIH1cblxuICAvLyBGcm9tOiBodHRwczovL3JlbXlzaGFycC5jb20vMjAxMC8wNy8yMS90aHJvdHRsaW5nLWZ1bmN0aW9uLWNhbGxzXG4gIGZ1bmN0aW9uIHRocm90dGxlIChmbiwgdGhyZXNoaG9sZCwgc2NvcGUpIHtcbiAgICB0aHJlc2hob2xkIHx8ICh0aHJlc2hob2xkID0gMjUwKVxuICAgIHZhciBsYXN0XG4gICAgdmFyIGRlZmVyVGltZXJcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIGNvbnRleHQgPSBzY29wZSB8fCB0aGlzXG4gICAgICB2YXIgbm93ID0gK25ldyBEYXRlKClcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzXG4gICAgICBpZiAobGFzdCAmJiBub3cgPCBsYXN0ICsgdGhyZXNoaG9sZCkge1xuICAgICAgICAvLyBob2xkIG9uIHRvIGl0XG4gICAgICAgIGNsZWFyVGltZW91dChkZWZlclRpbWVyKVxuICAgICAgICBkZWZlclRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgbGFzdCA9IG5vd1xuICAgICAgICAgIGZuLmFwcGx5KGNvbnRleHQsIGFyZ3MpXG4gICAgICAgIH0sIHRocmVzaGhvbGQpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsYXN0ID0gbm93XG4gICAgICAgIGZuLmFwcGx5KGNvbnRleHQsIGFyZ3MpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlc3Ryb3kgdG9jYm90LlxuICAgKi9cbiAgdG9jYm90LmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gQ2xlYXIgSFRNTC5cbiAgICB0cnkge1xuICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcihvcHRpb25zLnRvY1NlbGVjdG9yKS5pbm5lckhUTUwgPSAnJ1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybignRWxlbWVudCBub3QgZm91bmQ6ICcgKyBvcHRpb25zLnRvY1NlbGVjdG9yKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuICAgIH1cblxuICAgIC8vIFJlbW92ZSBldmVudCBsaXN0ZW5lcnMuXG4gICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5fc2Nyb2xsTGlzdGVuZXIsIGZhbHNlKVxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMuX3Njcm9sbExpc3RlbmVyLCBmYWxzZSlcbiAgICBpZiAoYnVpbGRIdG1sKSB7XG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHRoaXMuX2NsaWNrTGlzdGVuZXIsIGZhbHNlKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRvY2JvdC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGN1c3RvbU9wdGlvbnNcbiAgICovXG4gIHRvY2JvdC5pbml0ID0gZnVuY3Rpb24gKGN1c3RvbU9wdGlvbnMpIHtcbiAgICAvLyBmZWF0dXJlIHRlc3RcbiAgICBpZiAoIXN1cHBvcnRzKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBNZXJnZSBkZWZhdWx0cyB3aXRoIHVzZXIgb3B0aW9ucy5cbiAgICAvLyBTZXQgdG8gb3B0aW9ucyB2YXJpYWJsZSBhdCB0aGUgdG9wLlxuICAgIG9wdGlvbnMgPSBleHRlbmQoZGVmYXVsdE9wdGlvbnMsIGN1c3RvbU9wdGlvbnMgfHwge30pXG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9uc1xuICAgIHRoaXMuc3RhdGUgPSB7fVxuXG4gICAgLy8gSW5pdCBzbW9vdGggc2Nyb2xsIGlmIGVuYWJsZWQgKGRlZmF1bHQpLlxuICAgIGlmIChvcHRpb25zLnNtb290aFNjcm9sbCkge1xuICAgICAgdG9jYm90LnplbnNjcm9sbCA9IHJlcXVpcmUoJ3plbnNjcm9sbCcpXG4gICAgICB0b2Nib3QuemVuc2Nyb2xsLnNldHVwKG9wdGlvbnMuc21vb3RoU2Nyb2xsRHVyYXRpb24pXG4gICAgfVxuXG4gICAgLy8gUGFzcyBvcHRpb25zIHRvIHRoZXNlIG1vZHVsZXMuXG4gICAgYnVpbGRIdG1sID0gQnVpbGRIdG1sKG9wdGlvbnMpXG4gICAgcGFyc2VDb250ZW50ID0gUGFyc2VDb250ZW50KG9wdGlvbnMpXG5cbiAgICAvLyBGb3IgdGVzdGluZyBwdXJwb3Nlcy5cbiAgICB0aGlzLl9idWlsZEh0bWwgPSBidWlsZEh0bWxcbiAgICB0aGlzLl9wYXJzZUNvbnRlbnQgPSBwYXJzZUNvbnRlbnRcblxuICAgIC8vIERlc3Ryb3kgaXQgaWYgaXQgZXhpc3RzIGZpcnN0LlxuICAgIHRvY2JvdC5kZXN0cm95KClcblxuICAgIC8vIEdldCBoZWFkaW5ncyBhcnJheS5cbiAgICBoZWFkaW5nc0FycmF5ID0gcGFyc2VDb250ZW50LnNlbGVjdEhlYWRpbmdzKG9wdGlvbnMuY29udGVudFNlbGVjdG9yLCBvcHRpb25zLmhlYWRpbmdTZWxlY3RvcilcbiAgICAvLyBSZXR1cm4gaWYgbm8gaGVhZGluZ3MgYXJlIGZvdW5kLlxuICAgIGlmIChoZWFkaW5nc0FycmF5ID09PSBudWxsKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBCdWlsZCBuZXN0ZWQgaGVhZGluZ3MgYXJyYXkuXG4gICAgdmFyIG5lc3RlZEhlYWRpbmdzT2JqID0gcGFyc2VDb250ZW50Lm5lc3RIZWFkaW5nc0FycmF5KGhlYWRpbmdzQXJyYXkpXG4gICAgdmFyIG5lc3RlZEhlYWRpbmdzID0gbmVzdGVkSGVhZGluZ3NPYmoubmVzdFxuXG4gICAgLy8gUmVuZGVyLlxuICAgIGJ1aWxkSHRtbC5yZW5kZXIob3B0aW9ucy50b2NTZWxlY3RvciwgbmVzdGVkSGVhZGluZ3MpXG5cbiAgICAvLyBVcGRhdGUgU2lkZWJhciBhbmQgYmluZCBsaXN0ZW5lcnMuXG4gICAgdGhpcy5fc2Nyb2xsTGlzdGVuZXIgPSB0aHJvdHRsZShmdW5jdGlvbiAoZSkge1xuICAgICAgYnVpbGRIdG1sLnVwZGF0ZVRvYyhoZWFkaW5nc0FycmF5KVxuICAgICAgdmFyIGlzVG9wID0gZSAmJiBlLnRhcmdldCAmJiBlLnRhcmdldC5zY3JvbGxpbmdFbGVtZW50ICYmIGUudGFyZ2V0LnNjcm9sbGluZ0VsZW1lbnQuc2Nyb2xsVG9wID09PSAwXG4gICAgICBpZiAoKGUgJiYgZS5ldmVudFBoYXNlID09PSAwKSB8fCBpc1RvcCkge1xuICAgICAgICBidWlsZEh0bWwuZW5hYmxlVG9jQW5pbWF0aW9uKClcbiAgICAgICAgYnVpbGRIdG1sLnVwZGF0ZVRvYyhoZWFkaW5nc0FycmF5KVxuICAgICAgICBpZiAob3B0aW9ucy5zY3JvbGxFbmRDYWxsYmFjaykge1xuICAgICAgICAgIG9wdGlvbnMuc2Nyb2xsRW5kQ2FsbGJhY2soZSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sIG9wdGlvbnMudGhyb3R0bGVUaW1lb3V0KVxuICAgIHRoaXMuX3Njcm9sbExpc3RlbmVyKClcbiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCB0aGlzLl9zY3JvbGxMaXN0ZW5lciwgZmFsc2UpXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5fc2Nyb2xsTGlzdGVuZXIsIGZhbHNlKVxuXG4gICAgLy8gQmluZCBjbGljayBsaXN0ZW5lcnMgdG8gZGlzYWJsZSBhbmltYXRpb24uXG4gICAgdGhpcy5fY2xpY2tMaXN0ZW5lciA9IHRocm90dGxlKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgaWYgKG9wdGlvbnMuc21vb3RoU2Nyb2xsKSB7XG4gICAgICAgIGJ1aWxkSHRtbC5kaXNhYmxlVG9jQW5pbWF0aW9uKGV2ZW50KVxuICAgICAgfVxuICAgICAgYnVpbGRIdG1sLnVwZGF0ZVRvYyhoZWFkaW5nc0FycmF5KVxuICAgIH0sIG9wdGlvbnMudGhyb3R0bGVUaW1lb3V0KVxuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgdGhpcy5fY2xpY2tMaXN0ZW5lciwgZmFsc2UpXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZnJlc2ggdG9jYm90LlxuICAgKi9cbiAgdG9jYm90LnJlZnJlc2ggPSBmdW5jdGlvbiAoY3VzdG9tT3B0aW9ucykge1xuICAgIHRvY2JvdC5kZXN0cm95KClcbiAgICB0b2Nib3QuaW5pdChjdXN0b21PcHRpb25zIHx8IHRoaXMub3B0aW9ucylcbiAgfVxuXG4gIC8vIE1ha2UgdG9jYm90IGF2YWlsYWJsZSBnbG9iYWxseS5cbiAgcm9vdC50b2Nib3QgPSB0b2Nib3RcblxuICByZXR1cm4gdG9jYm90XG59KVxuXG5cblxuLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBXRUJQQUNLIEZPT1RFUlxuLy8gLi9zcmMvanMvaW5kZXguanNcbi8vIG1vZHVsZSBpZCA9IDVcbi8vIG1vZHVsZSBjaHVua3MgPSAwIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBIiwic291cmNlUm9vdCI6IiJ9"); - -/***/ }) -/******/ ]); \ No newline at end of file diff --git a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.min.js b/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.min.js deleted file mode 100644 index 4468ef4ee73c..000000000000 --- a/documentation/src/docs/asciidoc/tocbot-3.0.2/tocbot.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=5)}([function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){var o,i,r;!function(n,l){i=[],o=l(),void 0!==(r="function"==typeof o?o.apply(t,i):o)&&(e.exports=r)}(0,function(){"use strict";var e=function(e){return"getComputedStyle"in window&&"smooth"===window.getComputedStyle(e)["scroll-behavior"]};if("undefined"==typeof window||!("document"in window))return{};var t=function(t,n,o){n=n||999,o||0===o||(o=9);var i,r=function(e){i=e},l=function(){clearTimeout(i),r(0)},s=function(e){return Math.max(0,t.getTopOf(e)-o)},c=function(o,i,s){if(l(),0===i||i&&i<0||e(t.body))t.toY(o),s&&s();else{var c=t.getY(),a=Math.max(0,o)-c,u=(new Date).getTime();i=i||Math.min(Math.abs(a),n),function e(){r(setTimeout(function(){var n=Math.min(1,((new Date).getTime()-u)/i),o=Math.max(0,Math.floor(c+a*(n<.5?2*n*n:n*(4-2*n)-1)));t.toY(o),n<1&&t.getHeight()+ou?a(e,n,i):l+o>f?c(l-u+o,n,i):i&&i()},d=function(e,n,o,i){c(Math.max(0,t.getTopOf(e)-t.getHeight()/2+(o||e.getBoundingClientRect().height/2)),n,i)};return{setup:function(e,t){return(0===e||e)&&(n=e),(0===t||t)&&(o=t),{defaultDuration:n,edgeOffset:o}},to:a,toY:c,intoView:u,center:d,stop:l,moving:function(){return!!i},getY:t.getY,getTopOf:t.getTopOf}},n=document.documentElement,o=function(){return window.scrollY||n.scrollTop},i=t({body:document.scrollingElement||document.body,toY:function(e){window.scrollTo(0,e)},getY:o,getHeight:function(){return window.innerHeight||n.clientHeight},getTopOf:function(e){return e.getBoundingClientRect().top+o()-n.offsetTop}});if(i.createScroller=function(e,o,i){return t({body:e,toY:function(t){e.scrollTop=t},getY:function(){return e.scrollTop},getHeight:function(){return Math.min(e.clientHeight,window.innerHeight||n.clientHeight)},getTopOf:function(e){return e.offsetTop}},o,i)},"addEventListener"in window&&!window.noZensmooth&&!e(document.body)){var r="scrollRestoration"in history;r&&(history.scrollRestoration="auto"),window.addEventListener("load",function(){r&&(setTimeout(function(){history.scrollRestoration="manual"},9),window.addEventListener("popstate",function(e){e.state&&"zenscrollY"in e.state&&i.toY(e.state.zenscrollY)},!1)),window.location.hash&&setTimeout(function(){var e=i.setup().edgeOffset;if(e){var t=document.getElementById(window.location.href.split("#")[1]);if(t){var n=Math.max(0,i.getTopOf(t)-e),o=i.getY()-n;0<=o&&o<9&&window.scrollTo(0,n)}}},9)},!1);var l=new RegExp("(^|\\s)noZensmooth(\\s|$)");window.addEventListener("click",function(e){for(var t=e.target;t&&"A"!==t.tagName;)t=t.parentNode;if(!(!t||1!==e.which||e.shiftKey||e.metaKey||e.ctrlKey||e.altKey)){if(r)try{history.replaceState({zenscrollY:i.getY()},"")}catch(e){}var n=t.getAttribute("href")||"";if(0===n.indexOf("#")&&!l.test(t.className)){var o=0,s=document.getElementById(n.substring(1));if("#"!==n){if(!s)return;o=i.getTopOf(s)}e.preventDefault();var c=function(){window.location=n},a=i.setup().edgeOffset;a&&(o=Math.max(0,o-a),c=function(){history.pushState(null,"",n)}),i.toY(o,null,c)}}},!1)}return i})},function(e,t){e.exports=function(e){function t(e,n){var r=n.appendChild(o(e));if(e.children.length){var l=i(e.isCollapsed);e.children.forEach(function(e){t(e,l)}),r.appendChild(l)}}function n(e,n){var o=i(!1);n.forEach(function(e){t(e,o)});var r=document.querySelector(e);if(null!==r)return r.firstChild&&r.removeChild(r.firstChild),r.appendChild(o)}function o(t){var n=document.createElement("li"),o=document.createElement("a");return e.listItemClass&&n.setAttribute("class",e.listItemClass),e.includeHtml&&t.childNodes.length?u.call(t.childNodes,function(e){o.appendChild(e.cloneNode(!0))}):o.textContent=t.textContent,o.setAttribute("href","#"+t.id),o.setAttribute("class",e.linkClass+p+"node-name--"+t.nodeName+p+e.extraLinkClasses),n.appendChild(o),n}function i(t){var n=document.createElement("ul"),o=e.listClass+p+e.extraListClasses;return t&&(o+=p+e.collapsibleClass,o+=p+e.isCollapsedClass),n.setAttribute("class",o),n}function r(){var t=document.documentElement.scrollTop||f.scrollTop,n=document.querySelector(e.positionFixedSelector);"auto"===e.fixedSidebarOffset&&(e.fixedSidebarOffset=document.querySelector(e.tocSelector).offsetTop),t>e.fixedSidebarOffset?-1===n.className.indexOf(e.positionFixedClass)&&(n.className+=p+e.positionFixedClass):n.className=n.className.split(p+e.positionFixedClass).join("")}function l(t){var n=document.documentElement.scrollTop||f.scrollTop;e.positionFixedSelector&&r();var o,i=t;if(m&&null!==document.querySelector(e.tocSelector)&&i.length>0){d.call(i,function(t,r){if(t.offsetTop>n+e.headingsOffset+10){return o=i[0===r?r:r-1],!0}if(r===i.length-1)return o=i[i.length-1],!0});var l=document.querySelector(e.tocSelector).querySelectorAll("."+e.linkClass);u.call(l,function(t){t.className=t.className.split(p+e.activeLinkClass).join("")});var c=document.querySelector(e.tocSelector).querySelector("."+e.linkClass+".node-name--"+o.nodeName+'[href="#'+o.id+'"]');c.className+=p+e.activeLinkClass;var a=document.querySelector(e.tocSelector).querySelectorAll("."+e.listClass+"."+e.collapsibleClass);u.call(a,function(t){var n=p+e.isCollapsedClass;-1===t.className.indexOf(n)&&(t.className+=p+e.isCollapsedClass)}),c.nextSibling&&(c.nextSibling.className=c.nextSibling.className.split(p+e.isCollapsedClass).join("")),s(c.parentNode.parentNode)}}function s(t){return-1!==t.className.indexOf(e.collapsibleClass)?(t.className=t.className.split(p+e.isCollapsedClass).join(""),s(t.parentNode.parentNode)):t}function c(t){var n=t.target||t.srcElement;"string"==typeof n.className&&-1!==n.className.indexOf(e.linkClass)&&(m=!1)}function a(){m=!0}var u=[].forEach,d=[].some,f=document.body,m=!0,p=" ";return{enableTocAnimation:a,disableTocAnimation:c,render:n,updateToc:l}}},function(e,t){e.exports={tocSelector:".js-toc",contentSelector:".js-toc-content",headingSelector:"h1, h2, h3",ignoreSelector:".js-toc-ignore",linkClass:"toc-link",extraLinkClasses:"",activeLinkClass:"is-active-link",listClass:"toc-list",extraListClasses:"",isCollapsedClass:"is-collapsed",collapsibleClass:"is-collapsible",listItemClass:"toc-list-item",collapseDepth:0,smoothScroll:!0,smoothScrollDuration:420,scrollEndCallback:function(e){},headingsOffset:0,throttleTimeout:50,positionFixedSelector:null,positionFixedClass:"is-position-fixed",fixedSidebarOffset:"auto",includeHtml:!1}},function(e,t){e.exports=function(e){function t(e){return e[e.length-1]}function n(e){return+e.nodeName.split("H").join("")}function o(t){var o={id:t.id,children:[],nodeName:t.nodeName,headingLevel:n(t),textContent:t.textContent.trim()};return e.includeHtml&&(o.childNodes=t.childNodes),o}function i(i,r){for(var l=o(i),s=n(i),c=r,a=t(c),u=a?a.headingLevel:0,d=s-u;d>0;)a=t(c),a&&void 0!==a.children&&(c=a.children),d--;return s>=e.collapseDepth&&(l.isCollapsed=!0),c.push(l),c}function r(t,n){var o=n;e.ignoreSelector&&(o=n.split(",").map(function(t){return t.trim()+":not("+e.ignoreSelector+")"}));try{return document.querySelector(t).querySelectorAll(o)}catch(e){return console.warn("Element not found: "+t),null}}function l(e){return s.call(e,function(e,t){return i(o(t),e.nest),e},{nest:[]})}var s=[].reduce;return{nestHeadingsArray:l,selectHeadings:r}}},function(e,t,n){(function(o){var i,r,l;!function(n,o){r=[],i=o(n),void 0!==(l="function"==typeof i?i.apply(t,r):i)&&(e.exports=l)}(void 0!==o?o:this.window||this.global,function(e){"use strict";function t(){for(var e={},t=0;t

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Ó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 ^ij~u(C>=z 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Õ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%0Anb1GgP zHLmT@=bjtdF<%_)3zy@KxKm_yan8p2iFC`Nozc5`eT?sDye9%m`tc!{fD zo34-Vl9MCO_C=6=;&i^A){M1J+`np-2MRSWC4p~G#Y=j@(u`OH2E&Z+X75Poz3(mC zQ@8BG+Qmtsk;`sh-XiEW$CFK&~|tKG6$?7)xFu zYa@FTjYJ)tS9hgfuiMfxGRV{^C)YRM?h}{&Y5R@O@~i2-QGF)vy!qy)X`+qmg7q~J zD-uI|g^TQ=JgK5jlh5crGRk+acDyi{ygOwi%@ON7>ERxuYYQa4Q*RN{1Z3rGVu_9* z0mOIGqwA;A$0x5R-h=53B$}>oC=n2SZRGs7vxj&8h3xleAr0HEbpA ze)bLj>+$%pQ`$}(aTh(1HaC_0pus>5ki<0c(Pkazv zMJCa^NR3~3=Y(0a9W&_rnl?xOi630J)-xsz^o@W}RnggGGTpX;Z|)ZoZ>Hy_)0M(3 z4Wzxm|7 z#q;xL7d~|#z1P$@SA#o{HU=s(Q#;KR$m&(PY6Gp>uz~E|;1}E(Qb%V9Gw9u9ytZEl zf(sU|nrtA}ji$H&C@8*1w@#l(R@_9{}u@q?~^IEDt#x zSo_8?>nfJm0^&Nl`VKnSu=D4rxNOtrvQF^6sl1clN}PP7X65q5 zZ@#r?*@~Liw~d%SeZ;mqN6wfrLR*)XfsE1MJw-3BJynp@puo_trL}`M{78n~aeP$i zOna$c$Ye47iarkN+rM|xzcmLZs1|E3i^cLs_ef(Lm<6iw=a-TG;=z3jyPHh=-gl>d z`Nn{#PahliaJ`=V_@24}w%&jZ;I1RJs`_#4# z#BlGx35U`JHQ~mc#qnbo=KEjntzXrnC}(+><=wJPt=ij5 zr@-m1`7^TTm9{dq%xwb|(aLU|!|=mlpl?B21g6O>qu*|(-|~<9B|0A_hVT~`df*8_ z9zsk&Y69%3Ah{_5q3J4mFWtG}%~Sq|;a*@U_U4Pk7v6Y-hj2P~dj#SV{Lu>M+LchSq`Ti0GsVCibKNwVoY2-us}Q*yz`Hz4B@uFsZ-&SI&?z z^j>m|?4w6WHww{UT6#kamOpw26O+Y^5Cb4C-9SIw$kTW0-+j+7HvU%e9QZQ^^GS3h z*`uLd05()GTPzUhb`t|=FLFq{mpn-a@cz9Le6CnEzmnfGUpt=JSOZ zqY{GZ{ z9y8qH7V5w4o;M?Uc0O$Mq2*m%CFZ9km~Vvz0;r=G0%7D7Z773ZekMP-g)|^ucfBDX z+Dp9S9C|UbL2!#_2!QsLnlJ}fY=b}Af259e5O=x9HmLUwvSW0WKk8e(L_9E!I*dI&wYy(^s#= z{d-180ME#A5drYaD6ioXD_M+$KYGX0&$8!tIMCICK}K8aM^2nEhVD!_e_oz*Q}YZ& zx%uN53;@(bP6R^wxvnq@zm)$(6-<%9&-lT!pW0XqgFndvUKEUv!KjJ=Ad2(l5DUNf z_}LiPFpIDA;0aqGyMnOY4H1_n;vx`?dpyD~{GB~pMnUGyH=5#4SL>10T)>`@skCmjSi%lr?MoqJim-Jsuc3`^NyovD`P5E~1X$ z2%vr6@Dk187wszOE*>!*o^1?KqW);8>f2IeM*xuNC|8(AKu{q}iUoUU$KHT;p7Qkn z1TI6zsKY;2vzQNmqVpwH49GSN`S8#e0b7*7Q56Y-x|$UK5rFL9q{KqXVIk{S zEQmkoq?r^C>44ynX;Z7}zdslA2{46L-w6c2XN1UQja?~9OspI(vYN$+_`^@PJ6Kfg zRtOrIHj3_xIrlvdSnhHQBU${(1$pj{`8ETbwo8k&xxz^NGBs~fg_C&pJ6u!h2cy+b zR7oJ+Fw0kniC_E$J_1cNv<^To!}%#~v`GNi#RhfgiC?_;xdotj@I*jzP7{R^07yE_ z6_Vl?;wn{Oik4>s@Hx2rI|YS-K%3mXz$clxeXtF-tqCeaVS zf=5IXxe@@%_dKFl0s>0T(HI2V6{1;QrZrU^cvzI8#T)=l!D@3xwFH2cPEv)q_yzhW z7UR(Ovat@Y4f_I8B&-pn6KiP}LXr zKHzo6NiWTgVZbC#aTo~f)SL#s*a9agFId+0E?c9$7PSDd{9mmT2lhOFH2pn`utJ*~R%2 zMh#fHY4(O4Wy?F7)p*ssmk4pFUOccQAEu6goH4KnS^-ClF_tJV1bwDv1KmL;t`nb? zDOhg!;u%j^xeNGg@wtgFz4Ve33;*`XS4lUwaoC2dy*%lMlc0srxB|9yKy=%5-z{CU zqeunqmQpyhtN5FEl*Tsr!PB#X;sDyXO@Y(^(}IcQ38zFP6w) zkKEC}ZKgfDWQ!+N*Dvl}F_CnLS`;BV9++Hn!?0aW;3WC!9vugF&w|M*_r4U%R%d8x zV1+P|G-7Y67e6Mx3*jiwZlF)ppDA6R;n|JnPpA9m>UeV5%u5*PO$B=$pmRy}|3{F@dnPTIO@ zVeB?f%2jR~P_b-E=MKePr!O8dxc*}Io^zbg`R$|gi-*q<-(IfGky-acguH!bT~ zJ*Gn$NY~>iUGMl)N~Vtu3O~THhUW7-B^g`NVc1|v#@^qtd@Y{i|_{ z{vCFf0LD@D_UwV$^8{=f{?^`iE%Y^R`H>F$;YT|B#~;bQAATec{Mh*mIuFhgSaAAF zvhK6b$=cJ!Z_*8KyhS&kdXvn3<1KRIsV+^ONTAB<;zh_BbNG_Zha4Avg*m=Ow?Ia7 zSVow!?-L8W)qU8N*WKsZ{HsC=pC=z&Azi$ljNr)|W3HS&ZgB{ndpE<`30H$kbPG2y1^rJr9z$>Sg$N3Cbg*e(19IlWg%D&Oc2@jrpa~1lP&wUoI4!`(3CE^Nc zX6FMX%tsTFrTMYc$3#KZG5FvllQ2& zI;2sbdU1txaGr|6!Hz_p{Bi>~@yhG2$5|wg-9$al&bTT&%Pv7v?=dQwN zrmSLj-_HYG^ztqqSBI~fKEdM(iRbf#4^O@;hcWH?E9X09|8D0V<%;rqH5kqJDIr%# zC!eQ?fFI}5CSyN?4Rq)@Z}uO|>0!vCxeBr z11+AzNGTHu;(mgI)_&sn(0bj=KfaH)X_M*5_b=)m@tzLmMAL|_Pkp^`=qJb{BmjQ_q_SC%$JPms?YVdicdjxpaXS(q(I>zh9 z3wQg=PnFJler&Z1(68|j<99w(KeDl?VUGtsO*-3@#xP=dd88+lh_9VNrJPtHtf-l zbZ=`79`*#Xr#I|M{?3}Z@E~b)+J3I2_l^fsd-7frcs%GMr3IfhuDmcYN$lto#3ZK= z+Q?~RoT-IFx<1HmfIY!Yc1zgh^sd}dlCrwKT%X`3!+l`!N*9l`NcF&RE0Q%(+)|tB z#s`L5!qOCOaHeiN1iULr(gbXJcUdpf8%_dMa(5__mwcZ9 z1D8hT%QSSRma#Bt$&#wDcuDJ&!2WSN6iLj7286ruZs>HFf1tRfw5&J4umE>Raz}m<8%;mO^6PqM`{nf|4oXdE|N$bm~j}zNv(9QXb z3!Bc_fAAdZAUNfUQ*0cx_#E}ZbO(p;lGg6D^e*c;X0u3^oww&?TSc+x(4OO8)(yS5 zO*d3O66}(upJBEL+HiiKLCJtGr`63Y?|bWM&-$jy!DwT!tUs);r|*C%2iA*ZT{8>Y zWv`=5cFG{!l~xrN3O z8uTt&=v`Jij_GXI1y&}Q2)Yj)A4=LJXg>N2v}faMs8d1)o_Lu)fFlW`KaM(R0yQ2A zf@b4|N|lrn9F2FYC^3ZRf(vN(8D(Wqw%Scu4mlkk;`b7L6I` zN7gq)LfH(l+K1ty6^yA!<6tz2(xFix4``SmptAl#<7*0)eLc&xTlrZqh|}>&$pk`L zE4~cxw8qh#jk@?en6pAU1HiJl7ao6&_S9cM)e)OZHLj}0Y#fJWTS*?}$s&c&-k$*- z0{(!|jp;%PgRxyS@Yc1Ej*kyu4z3BQx0kz#CMV(_6BYK~Up7g%57SgGu3d{XN0 zz?H~fQkPe_THOx?keL#GtTm&zq+`oDFv>ILmU3wDcq`lR%fhQlSTQ;i*YT*Wi!iIZusbV-TfC7Hl8 zu0cTtEDzwYD#l9gtO0LOUSJu zeZ_oSZG!bOu^mYn9hG_^KS^z)t)9|1u#wc&lsX9D#r$3LmUR16&SZ(?&{IM6qPY!a{3npcG1D>geI4iE-WO_x+V>qe0IqIatdG)1H7?ez zZjja_z*VgupP29|9sD`{RIa|E`1>U-LiW$|L-kRt{+{W8mkFBZkQ>%q_N;rRW6}o1 z8}KJ;B#07d?&8KZ8AF+2Mn2t zFwlS%3oZjmzI#3cSn-eL4+#;mR6@hI9&~kOMB zR5;-;ALDlZc7JJtJ|d-<#w8!21(7<^z{2{WC+)I`k^32J5CTn!y;v=`6uM*)1J?la z34D`j^jss%{|HT{Q949ZWkC**i@wQxc#Z-ZLz8I;cL{1`Y%-0~;T1e!2s`BrYF80( z`fwbV1hbVE*d@L-mkm2H7Q*faU14Q%Ih=()kh>0MdPi`hx$)d2ZW=d>o69ZaYPeucZ-?eLUTgGn4X-!&xQ_RJZsOjrecu-@Z}rgD zS4|IvPDnT7Eru^wtXM&7ma{invx2O`U+{%4S;4P$eTOT;dbgjDK(|?Y1)kN{d$|aY z>+9ugrOchBVEQHSi1hACqp$OF5lh6xu4Eci{94y7tP9I|Ipzd4ba33gzZ?0`gOroL zWFWbYTu(-j(PTWCM5d8ha0dE9QbU%Jm1H$pM>dfj-ZdVT~ynjgU^ z`ns;9@pu1n)BV!)SNh!V{rN!K;d1NgFJE8xwb#>R{zBmo|ETmKy^HD}(szgFCFx3| zuN%_!hNf>zcYh8fk(B1Az>{8s4+Ka4${d){t@&!&pTfD8^S%aXA%N5W)2w zFFIE6M(q_TvCz!>b;tw~=)#-2E9I<@@}EXRWrzthrIfQF7V9E?$9Gn>CVm=XmBjv1 zO4%Zwz*5R}WR&#vNYk_unt88_+%BrxVcRLFus&$FfJQ9q?xnCgr$0A{8^R6eZh)Ba z3EUKJ1~;3V&n@Pba?80@+*)n}w}rcdyNkPBM zdxLwEdzbrw`-J;~JHvg${hRv{EG3Z;q9?&5jF?CaNg&CvU%i!N!NHh0B%gGEg|6Lk zY>TnvH}L|0mjw@tX!->!AXzr}`M>l+(gkr^dFOdWQr>SNOo+of{D*!oeSvon3(oKG z1;mH?CwvEaqq%a07d1tw0XTtyFoIG5>5HIJs{e&#tXKhhwA))ybG!f@5rq}|1YSom z<@^r4V7U4{umm zUF0&QIxdHQP54W6AM&?Lej{(bj38$7OH+j?6Fk#^Q%QD1Db71@Xi@PUhA*a z%@em*OjsTxg4gmOhL_b(c61T$#!Gwk2X$Yf#}UsR&>w6#qVHCv2jR@C?m zfBxAXK6m%$)dv=fCu;T`Sj^`xK0w;;{`~XZeD0plFbQ7SS0kQSeBb~eRLa0Pc<@Ur zh_LOPsDx_qAYb9c2J2{~^`P$0qMt~59-N&-^>XHe6;oc28-3-}DfJ8Ltk>Xi!viZ7txf;{Bp)1l@+&RhC{eKS;ChxJ z%bFDeO^QXb!Wj%iRIP>GeShOge$al=Koa-U&IkuiXjjuG7*-dUxM-C}vlZ7C_EFF0 zI&hu2?p!I?3w)XbG@8?Nl~;3xtUGN6zotZAOA5(1!p1Kt1h(HImN@tY-|(06@_yCh zZVWu4dP=#EpK-+I<*s~Hkju^{F>yATf)AEjrdT!%88YNT<&YutT&acJYoVQ_-tEQ%ch-D~FWBHBx1vV@lIWA!Loe%j8dfi$%;TweYj# zba0Q|S3ZT8EsfumT7jVDe#kf`x* z!pDwO=m&&@Iv6q}Jg{dnF=WvHYaB+}2s5#MP&e0o$O}{G(}Xl7l}_&{dQo^;N(@zn z{MvI-`Uc%oIKo;XaYI7^|3#GU0Vs=C-GkBFniecbxA`3Lq<9h%HU3?=&9MZMLO!j@ z0R9P~3iE+N`6tAAqzo=WKnSn8$Fu-qwi%@awY9aFh7LP-4)d6QX{^4vzBT3n`&8?j zHxB2^#3cPcFb~%~$OG=m352tbB~l_WiO*@=$*}Y$96v-@FXzJ#5r5#z=wTiN3D3Fi zN%_DL7MOqxJSU~0hil;sAj18Fi!w&)mdJS+BY!>&#k{7QjCr{3Ik8{@X!(9pBJnly zfa5WSMMd9WUf&=liAlPr8ixagHS~qMNPkSAk8Rw^=Saz_8G+sC8_e@h(8KhwPz4nW zg?wDJM?8>EoRomPL*K8JQdOVBw!So0_qIe|JxqSSjWF)vzu><>EY5q72iz4*asmLr z(lngajT28wbprZ!lIhFyoe%}#pt;L1ALl)WMKBqq1l8xHB(x>Ts0Az)T$Ev}L|L+$u%Rr9&*SqT57#}&1MUJADM58(KbFQ}6$a4Z5|&FjhARCC>{r2pp~`X2aZZTg z%kW)@Vf9k(V}CF@Q>+meiHmsH;8RNJILEUqkf#8&a6JS1RB$uxQ{;NOpYA8uYoF%V z;8k)x%VW49L~jRuEKWL~l1qcY35ZQd3?Z~HeHs4xlE0E7`1@-$ zT}8ixzg6Js4u`**cf`jZ7x4wms!E5?;caztDV>P?ntF-T9nr4`RE!2XkcCVdzC~Nn zR^% zDXl*p4KtFnU^Wtc?XdL^Zu(-AKc%f~?77Ox#LE3E{Z#T(@>j|e<`=`i_4sxc-{_6_ zP9DW~aX-HE1?+nl_Ptv5UAoTFNa>|#SvD*~!2qc(@S^X*+w1rx8s5kdcoR3_x4ZG% zSm!r(4ezpa?1A^-7iIxExU2mlL6dCG_8W6+MVkrs_R55Jqsd@2#o9~;Q>2&n{PtV= z@Z$CBFRWj@_yahiz=P`wo_9n(PaAa$N_%Qsd-<1~pFXw$CPvrbsg)BgEce+Hnm&0i8iC&_(uZ)q_jJJej7#m<^ zt6mxugk+^-J)p>bNVoaYaAB#GjsUTsUcyo)>S1V*O3?p{_QgCwW1?k2oS_V4d;}B$ z8ZS}xA31X7QDyYNv<}WWLg1LEem+Ug!ACEZa--k)9j&Bda3E7BRW|^h-3His344gN zMp`NstB}UNLZG3uEcy-nTC3&|C3|#ZAJ@nU9$ z>ck9$l?Pmmp;MZLwOdQROo)N@fKik{yJ1kH5QC|!@p0WrWF3S9w^0W%@N!x?`q98k z-JG=^Lak9o2leuKN<7)8>VH4B2Kv!^SR_d{Y zfBwkYwMXz(y=u&uRrun|qzgyZO21bDT9>~8DGiLH^6`l;08TGHKBiw`TH^Evieuao ztMkR)&+;Ws=bAcOHw%;!Au7i2vBicdVv_*1;bkm&gqGy9C{5s`w(ieJ9@mljBua zDlPqh*OeB;R#XTswi7Sv7Ks%ZK1sxKJxz#QLk-0KHRAj$xtril?)24L{S> z4wwVx5EMT?Z%{$^*ozDqx1dMFPqdCM%kOK92HV zMR8&>a7KM3XEUY6V)vJ1lOh>Wb~rw{K>r-2kE9P!vD^%?ImBHg$TGTt9}-3Xd?6QZ z&oztXls~Dx^?0`co9S4E+_QEO0ss+JTN3 zN!V69Vm#9635r2U=)!#zD31!@y3ytbnJI!B@?&yGI49+IBUh}uO*aTy9ptJNIvC1T z-EEC$b+Ofs$BK2ajsd~|*>~bf%Th|IAPJUtBln!JM0nLbA7P2(q7YIoKJ%OqB3AJw z;xm8^e1XoiQi&`TB=Le9eGP8)%V59-u97}&e8|9aJGgz^6!1NQeTU%J0`>!TXSJm33*jTv$UbaV{E|Gy=-*xuf{5%2oJ%zno z*=L~{e|06&yI_z$v0%I^eHL075WNH^56!5UXf&g2YLn_AdNw)oEqW;;BI>y_AyKx) zZ!`-snS?fX8^hCtgsPDE=%5kNa0pJ=);vBjEXerw(o_Te`LHoPlAb>un@KNyliu=2 zlGHr*JV|M#e}7g zH2W2kDVgtZx5=C+#0?FLH#cj3f%K=3o&T0TM*5#W0oYQGpMaBwKLvIIj)MS=AWmNe zyB9yky$-y&@P!-L>H>ZnBM6l(SLcx4f%y zENggR2*yS%7xpZB0yqbFE7Jzq$zS28A;yST@eoCWu@KX-AIKh966A*^MH}H8=EQdO zhJ2;`;SuFw+;N%V4C4M>`q+&x#5QZQyG{I<_!)ijLy`(}j^vym-T2tB+;NkV;v%lQ zzM?p5$gQI`HOp*YIWN&1HSC7TQw9{33@wP?e0|5n#M$X39rH6%GAlcWho?6yUsGZ) z655vA7qsgTnG+f}w!^|nDSe7cdu693<+kf=h>8jo4(OWK{H;~1l3Q|* zOk}~$S;Ze);+D4R+@;D98=7n|7>q5WLV|5 zgZo)xOhvkc(6GwPtZs4fopSPqbl_X$n=|u^`ki0bvwUKgk>hVOnxjpY@Sxxp&C?CW zu&A7N^A|)#^=aES(@>gjDI(XW@?AT%YnRU3TBoK}b|Za-yf(1Lk#N;u1O@4C(GHhVrsz_^w6}@1|M5osU1w}{b1wOQWLHYXL z#z;eWgr1MoH5&v+}R?dU4|(k z=k<~f{hBAW$|Hl$o{Y7mr(0rAp5?&Llzz!#{Ls*bd!BoZdkfYB{G0okM3Q)jEy{s- z|5EZed5*kB-XWimugMR@!Rz=?KAKPFtq^ltz;^>GMUXh)a3k_DzL2To3gJ>VK}NOZ z#}%gAK(H3ZbtSk9cm}*|M)+BnO(J+(S9l)YviZUk9d<xB`BZKM%=m^>lX`048v_( zp3MLcz!vBR3vdL3Q9#mdQXYUbo50r;ER^KKa}fmch3%$|fC=b=;s*$aPqOM5^CNgh zC8QJ(r~tBMp42!dNPr6PI|GWxO63~0 zIIQ#b!D(OIm(n~bXUV$uiM0^H2zunYyuL$2`;?Rv z4^1u%Y9E^sADO-^&)71&t$x|8(Cdt5-W*P%f-;*&G>eUjFlWZcw(M>yZ{OvPkdpQ- z1{<&E;|!^ZBz<0LtBkVTR!^3ekIj!y6LNw(8j?-PiOnKoBAX>n=^xtlFSSK!RiKT5a zTegX{nS$09A7cxaDM-;U2f_hoUCid8=|s08=?)Nr9pAJa9u*s(kC9CIdEe|M(>2= zu!NZ58A0s?Rk`dmjy6>I3h3!X$w6nw;jrz7FCA!4$&U|TH=9+?%IWZgh z3@!|h%#Y3fOmpJXgT}EDqVeM`&FBn?ZCOb38Fi$)Y72hnZLvV02-K;1> zUU*d7QK8Xs9fA{+?zhGplTyQznn$%9niCxzbzk>lbGYfH)cC~o<}IQ_;$!2*XD!Jg z$^5yT0LA?C#bksjHwF0CBK0fSLT3QkSo*?yusdm`Fn!6zFX-i+WXJ+uM2M&x9wB|*$m4`<`Gix zGHs-T=xyR()>jRhU$bP>0`k;hv5+o#fb=6BNrE^*{PrU9jX@+$9#|mi20%)2BSIRZ+*5wxUAN4aQu$r2iCrgs^K$Ffqe_l9ojDpVARe(blx} zQ*;C$@z`TRXZo6Wk>CV&2+1QCDVQx_|G1uoh%MLCacRv+TAX0j3)*}>pzlwcM&Ca> z6$Z$Nsh+u3lWh9NgY^IY{&&&_uvJ`Y6h`Q$Vmug*G;t_tLG6SfpSWOBP$-PZkKf$u zo_)5*?x%#GFid=jyeSm%h4=3oaC<_*!j3$-G>l!Qtq&Z8EV$}RNxIMVgSZ5b{Ln>G zn8tF|eJqc0)5Py-n*)!4PVSnoX>z_*%_W}B zd*_sfG66wn*G`^Xi!Tq;+GE01N>>Y5iY|R>?5;P!N=rM;V!Aw$h0HJjeWnG0VVN;@ zL1C1n-J4qwwU^S0$^eevpu-!xAFr!Besn|XZT0{9SN(0N8;-*76Z@8@Y~R<|xNm#P zE&Hl#r%tJ_n>wYg@yWU=Q)}@>O6rauuiNmN@v}Sj?!DtP<7*r6_lg&ziSXdz!w*t1 z`o$Ge%DO32>frghTHq^h*o{1n=eA6t9UQ!agF0YGHHBFc$~E8E_uZo4T)yvwXFZNr z1KPTJK-~BwLjg#Hy?~R7h?59_(_2ks%v0q$us$(`3lV-24nkyDDpK7@5UNCGP)j5Y z$wgM-rxe;S6iIu$Zox1Tlw!8g*J`IssjZtlxlUMXhPz{L!<%)-yTe`a@RZuxDU+qW z8w9Q`{R#xs1@Kp4D@$!`(-a7T3+bh%je1tbV8nvyGcF7z?CS&tgyT!)o3I%`&}UqD zN~Et->guLUuB#JMRoE~xjth#_7en7I;f8YKxS8An?q=>bZX>r9RtfwW)(89@)&?Ah zbpc2v(C-wx1OzQMtMpsa|I9!`2vLPQW=Z*zlB4*|NK4fNAKPxH2!V%+ouwlkW$` z3JK=KJYn~Um>$tV!p%=_jxC;cd{tN8 zCr!!8;5kShD1UZHOHWUuKc~aLwd_)hWU@>b)<2(5(zPF7*s^6|N2|3X{g<5l9ZX1n zN>58mPmwRpmOq6-dPBY`)~M5kwT%i3(zoasmN_y!t$EJ@qir-Uwe8%wZBxk^+vov3 zo2P}3%nUowWk8!zquLDUaw;sUZJ17Hj5XyO^pP#}k2Y`K(;ggbr$y_JA78)a)mKS1 zgKRR5kUt-T;=cskdD8DlS`yyO+KT5xQuSTdw=OJfZSB}`fSi_2mJ`>@7w(Ziq5A>1 zx%1tP+)c19<$e{vy$dT)zJb*zBCI^YIi+8T_u3H~vSv6KYm&DExDYrFxJ<>BV7&;y zVqj&Z!&P{yJ1}pabdD^MKc%~HP#WZBh=FqAV!?XD zJSFLEm7h0jo^$3W-@ocStA8cpx|`@LbOijpa?^DYZA%_oXgP8F1N+w;&sg|aiCC{< zX;KsXRAhO#u=wb#`?KJGbbMI1^2n!xBX!?J($|sKk>?eDSGY7z#qW{HEwC$)QDyCQ zNrdG0H$*;++>TuDMA8_2?DxREa z-M6$87%Xi&mG*5-k%j~~IqJ~}+P~GH_K{(OdoEv7n%%C|w_RQ!MRgr! zS7023JEm4DOa@{$f;%OGWD3N98#@%*qTo9?NeT+%VAF@fSSKj`qeeRWGzEfsXkPq}vb7xZ%=4xE!uN3rp&TSNDT0Ss`-t_w*Z074`h zczlqiFkEr^7pw^hG4=^>ocMN5awoH;vu++4HS2@+BciPFvC-X@je2^*%h}_i<2pwq zEt>Gk&94&O)C5ah&y^(Xjq@*cxyf1_+6=&rn*Mg18=_<5tx;WXt~xaONM5zMQ?%K# zV9fKkd`nNl{2KEKLaatG$joHWA9BFrDTO^ahQsa~Ga%A!IqbOcF$eB6rM2_(&c`bb!m@349Wp}}yCv;=+(+V;rizC-g# zhifh<2|RAlk2NVhE@;azG{0)j)1Ujwg&WE;+jI!F*attZ`6N_xK}q0ogT!l6dR)lW zByb$PLf0+1DCdah&s5X5V6H0y=8;pt8oz;?&MkrUr8r)rlM;Fo4sD?JxqN}DD|o+v z{g%deZXSfT61>A>B|Wy{)l4Kzq;j>M812kuZ= zO*KkhNj9JtS~Chv1u*3iX)MtFXL<8=yL)b-XE(LUB&C_ddKPV=A1#d9V$Ufn-J<(? zP3JEPs-oiCUmuat@ta=Xbd1P|9%Ft}|NnS<6Zocz?QuMFZ*G!iYxZ|*ijVHeSj+8!s{`>!C@Iwkv>9waeY^rmkr$%&g#NHy8h3+AZH8;0$zT$GcVQ@=MWKgFT2O)T%}yK$)8 zoGA%cssb{!QFgmFN@#$W@O6`t3I^$OmS@Oinvhtuvn(XQ z5F91y77Y&fS1SF(D_`&2JxUcLlm{y!!!U}I$U{W|7~_ImBduI}=zMB8a6y z1S@}O=Fs(jv_O!HR7p7w!(rvLfeLb6b>&d2(Th0U)xq-AHt=O|KkI(-)xY@SN| z3-2=Xse6ut&<5eCZf*f%B^%qsZ1dSw#C|-$KVX2*5){jifwQ>vC3f1%^AO9Rd6$ji z?9}R}xtU9vbp8w-5E!6O${bo0rmHLISW?!Moo^Jq-n4AuMD2=>)zf2+#stp@o{*BT zq_JVjl;zD=sZHTq!nLEcBNC!Y!zY&p33J13MVoe{6vR+3J+rB;A~&PJp4<@gXpEvj zai%yYr})^GnVnmVLAAr$MjqW1N2UiA?})o zksDAc_Yjas8S){ug!@`@0+(P&XR|}+U`LG>K!w}B&%dS*=4B45D~L{@X_S~VMZ31C zlX|}7;Wr;V_bpz~6*9u1*Nn)D4JlHEimbgAQ`&}9#xslN`ss8lW|`l}_g^_NXmi&> zZuEhtI(Sn-wUu&556TU*!wzN7MfTiej~2 zcK*Tw!d}IPi3fJliqA_RQkS5JJuD_SwoFcwMr+mZM`t*bGaY#gv z)h4P=lq>P(FB>c~&=#Q8lfCcSsgCZA+GUexEe%+`dfK$fHl9Q!qsNHFvU;`7Z&-3L zm&>KcmH7G4K4yPsQ9ID&0DO@g8_T(vc(!o}#^Er=!~BUyo*4;PR)>?(vf3=P8B8`o z5`XlUcym}{wWy6+Y&T^(!&O|rhL*MQ_IG<><~ssynPF-8?bXa=XGR_!JC5cGf|G~& z>D2Wy5i^;VsX)cCO`bMwL3@$Y-wdGn@t4k;yiB{Xd-ZBi&u_!u2u=g=*e=d|&PoE3KdW;?Tz?c7?WmL}O)hM=SY z&uSY;Gte_x+H=61AK`xL_z>iPfik%dQ+N&&JC~>Bfg1^w&4UJU|FiRNYSN~5hsk1h zXJ%Fbg)jIYy&!A#YEO@$J=GHs3?N}LLBWvh^==eY+R^Sm!PzLlCr$ta4GBVDkUsba zy%dcjy%e`b^i|}MzD&P^rnnmq?{+t|z^QjP^hvYc-O&FqmfxL9fR47Zr0@W^`FQmc z(vL}-lyPb~3t@arMk9Z}Ps7H-CK%E>6B*JQpwU8*EsC924nc`zN)}Ryr9cTy0*nk= z!0H}ofa%-)5A7T0?q}9S+UUvtH&_KP^+mj4x>R`e2Ulrgs@*B@wb@RWFNlpUF`t~! zRqDH8T)FWd)lA*`9j+>T%owt)db+>R*V^Nsl;IqdpIoDni?x(YR#7v&D(OPw(kRUX z7G~t%Vzn$F;<^F1dUSop;(cbG+zD1hi#ii;9=dY?!rOt*gHod~n$X7|*tng^?I2{Uw9SkVb8rRSe^XC@XN3*qI^QiO|n zdJu3v=tD}lX;*P^zv$>j`n$>vcdrsKRv>!d4Lrg-NIw|hEAsY!zA~Sx^e~dm(4U}J z?S#USJW1OKIn}tF>E<~&q0na*a&|(z#_u@4z_?F|LfF2;^F`zz@Wi$T zI9CvLj>R8o5)Do6xbHzS%k|iF(mVQxGh~3zHYMpy>>2PcGSq=H8bqp2Qh8ya~JX&`Dk3YbRuN6vV zGT#Cd9WE4$g_2;?!!xFLbxcpRs+a&RU&Y&7aK;|fAq>Md(R7vmi zQ^$>)+IKxMU&*A7u!*(mXx=P|LM*hU2$dq=Sip5(&rrX?nTp}d3Tu0|mvL){870ag zxn){MslFgCpk+s5b87Y0I{(Dni1KvxaBE8t6Zc5ts8NlNOs#E8mj+d7!WBw&WX0ym z#h8nv0nG~8SY(SxE6Pu!r7mucf8MejZJaVI#6N$KHi}mER2Q|`?oH5U6w88Ag64IU z%NhT~XsUGKx{0GUY{*k`@!F*e@SYq#e^5X)H`Uiy6A^u$B;D^bY$)R^7K6*X(M{)CC70u1o9H z2BbLBMvbiOJDFiCA@kvhxSM~Tr(%8ILm*l!8I9cLk?r=1_N*W^*kIm?Ov6B*0}!F7 zX<$faAU%;CwQ{|e`KIH_Ra`K~(PNFk}qVrmPwe>O4-}%`yD@nV%rKMI_X%l%1dA5C#NBbB`hc9i8Y$Zmv%{DzGZTFMtJr zP?3>esGo_j4}L7T$N?vS1lFgEH9i2-fy(PGJZMpt6|f^};0c6L5avM2lSBFZ`{O2b zZ>V{~Q9uu;H#N8J>Ks;?BNM%_e70*ya71xsWpPCC_?{k=_>qv>;1eE>C}1c+_9isI8Sq zO+}--#@}~g=cD4W?TeSsD>-nccVeruZ+GsepXSP&$DhwFjnL~ON^{STZ$>MkqGlqM z$p0wF0PQV1@)?Nz^$q6-;QuKQaW@y0qFU65#zGv;HZ%t6ZZ*8A*H%4VQxBQ z-va;;pEyrpLPHV7wDfl%_C7X$VWTG)<7w^*8$N39Cp|E3;%qTVz;D z?a0^_eqRnVD@%&xhRUk+^fBq^nc9@FNSjfXrBtVOPo3Ibl$T$GZ)7nYS?}#>KmT39 zpg{%2d3nV%+uLX2pNfj66=fM!4b5uZ2*jkSLo#zjn)0H!xDj!^q%@mCJYu9oT=bqz zDGCkeOLB{(Qil{VzPxu$+Ry;}t=1F}iWrebsKwuCL|P&9cCc2ZkjaoQ<3K~zbWngm z7otPub$r!O6vYh7jZdpewN+N8L}d(4O-jx-nw+uGnqaL|b@{SNs`WKR$2v{M?Bt}> z!5L90m6f*Csceb*G$5HlFIOqF z4h44;mM_6F^!DOm73Ys1KVLCyF}i>+;s4_QZf|ejj%==6>co=nz55?|=HkU?9@)RQ zo0@|}_@{OFnfiK&RRR82_!4(B^G|lo5iEb*>=C3ka5v*cnqX6?=@}OLa6DAu7S3SC4dx|{e}t=bzr)at&$)rO5Q8|E!AIQ4jA!u< zHI%b;Cb1;RnVhXNlxyW1yIfmeb$$G*Yim~*HTG3X|0*@M3psATCV7B%4#L1<9CHTj zkwm}Y1H*J$3{EW#qXt;83Tvo{=;Ak!LJc|4y6 z;A!#{{3^|qUFHPdQIl4XkWi3TBhAZAPfbnF&683WUpf2|o_TZY9=v;5&-)XRaLeq9 z=J2?<@aBryTNbBI9{hgKvLRLX?nB!(qJTzIl}LlO@4L5Z$cx4u93 z(xq|uJNyog!%v~FexmBcRpvC;{Xbz18jLQWXe1wZ=_RTJZ^1eE0)Dd{O?ne?Pd`ig zM;q?utz=vf*<%G~Bf%UIxbOkIfV?D9*Mmkdps}+G?n_5Hf*b>PiQorBvL6(J85c;+~H?QOtknpGv-dL@?DcOXTIgi+=S)h>mTf$e!71A@`SlpzM2j*NYFH#jGKMDH0WR8&&bZL zgUy8<6tdRzTlCHjcN{QYcUlSABfbSOe9!UW?2k{Zy0E`RqUNzwuAYF9WlJX)Mn0 zn;-DTGv9$;MWX8k{XQlN$0SD%8j;8-T#j6&W#mZ18;?`)3H%&RMlZwIIS-v~!JF{U z=*#)+_N6w;(EcQ^^z=!75lFQ3(Y~fatF5rmW-X+?Am8Nb4*(B9t2ZpvceO#qA6;rKEU?)MASWDf z4lvUwm-7zq1ot!O#ca$;cIPsXnnWJ(PF!EkboU?JuoqmL$v-^C;ok8a8>_w-a-Vy_MGC!3{RnLC`Vn|;uOpNK6}#rf(p}*qr4X3hcqXOXUJ|+LFU^Ck zKP}H2TLb0wL+7p^DQ^I4Y%B8q0B>4g5gw>WN#5t~cIbz6pi~c}ZrY&M4G@VE*4l36 zA7p-j9=jfPo!P;8fODAhGUpO#u)iWM3IL(x02lox)QuLSd*IE4$%9xW(t*_=ftP!P z2P+gflV7A^}Cj z1?cDNg<@$h<702~3)UL^Ocg$YN3PHsV?cmWLtlAB;G->yGiZb3#%q0;Ua43J4+O;h zU!TJfgWF4n$ZtGqVf+KN2mKXMDsBzFc;N!Rh%6T_AWKiYLg3>Y@0$>+OYkl7^`YhQ z5%`KfR~a3xwt2MLS2O_tFyAI$?=IXB3@4W!1D>Z z&;%&WN1(v5{b%t5chRcS3{#d0SM(RvU-bLrP5p1(a|;sV0CZ=a7K@V{iP7*!Pe>Xm zleFPo{YW!a_yN-V>`gw*y;6x_0BHh=^j^kCJ3bDO9ap5i6WM?BIoIy6kZ7Bj_Ae;s zk9Td-$wz55Ml|9A3dipQQr}16=w{rVsE9Y@dLuBGrg88g~Y=n&3H!^S+6F?TX-h0c!7WEI^^_2b#X^eMoz&B@EI1z)cKy5*JiwcuY(T z83UB#Z}}9nleMjqSY&sxta^7aZ|f>DQU*P31dc!qlY9yb@lN;%(a*q>n$XWJI1j%9 zpFG%rCK*1@;wS0`4XPuD>)ZY_sv&n6-hp=v%k`VL^y0;(^T4p`RR$@Oee_mQRF=Dl z{sQXycB2No`_jUdD;NGhsuwUyc1&kgfHwMnu9v4ie!0V7S#k5Qzg;i9oUPL(ybFOk zMaD!R#y|deoj6YK3 z*9Qr3;!YTM7!q*jd)v0X_x{$c?^9bBk3T&A$Pjg3pL)mU!qr08J$F9x=fK6%akjpl3r>g3*^K&@k1i=P)a90)D)E z{*qBTD^Hjqzji0Kg6gP88z4;WOnmbu2X}|@(AqzM*#wFkK*g%_ zL@M`B&h$sSV7nw^CK*EnAjlb3I{C@SH{`4Ra|jZ6$IuAlV6{3!3d@R*LAk-V21dv+#euApT$3v4qfzAQ2Jmr z2n`yX5p;af(9)i74jlM~9Mre34B>w>vC(~u8-9%bWSrsd3C zu=T*V-;(^${-t;<)4@vu-6xdoL$||4unH~iHBwCiO53S`6c@wbqnKQkcb4j4@RdXAHf8p+^yR@{Tj_fX&7Lcrb#Jr|t&?=J&|pRqH)q;~nq8dpD8FuwVcVzCDKOa21u6 zg){mq$6}%q?Z@{YBiY=*01h^xy17|>&$`uDKHtmTP3AW7E8I2k4l|)biVRs{uNHQOQ$Z$PXdp>oNx+K;+S%7}*IaSR ziZVu|WM28~;%7alPW7OAyyv4UI~tp*)a5vNO0Lf2D+6B7rM18vJhS6oS&rIllQd&gETQ&VSfXl4(c z*^>dxc^7U(jTt?Cr(DB!y>@i&-v?VaF<@pHclW^bxQd z(^mmLHWC*DICNU|tnGwn08$~I6H!P`q#Av-?}g0Fmk{&VQ%^mHZ!D#$H5*r6Si1DW z%8h3-c_A5K4ZMl*-fg&+zWRDkXWzW8xlm=!qqtMh%Y4h$9~2A^-O&&zKn}u6M#C0( zM2`Z3VU+`iRj*VitqLVrAG8`l@5KA2#3oHR^Jsmlqt})+^6@vuC&f+KG--6p1IYP! zXQ;n!_7lkYKuaCB>fp;SJCgd-{?wXY5V?TFCBQeb1v56 zlei8x?<+>vdO8S?cof(1{{gn97>MT&{S$&)fK1|Z-3&_3vQLW{JXXML4k`-~1OyqG zNRf)X`z`+;0V^k`=GgKkpk}-bW5C6drrHN5FP?6uc`hlQLyi-MU^FHY!ADvEpwuZ8DUp-zOJyl+iSWKmN0gcqmcZ&xo#%E(As zvKlFF2wp>e_}Xh{@mC1+U;_Wm9eg1#4EPJ!q8YLl&F*kQtX(_Tpodld5N%g$l9Qnp z>2!P{UJCKait)1Zhflr$*!dLpC@gv5`NMCxzL~av|Fn5Kb~HCP&vvT0Hx$k}wY77c ziW`jDIh=b7vCm! zyw{})Bw))Oia&e&>XjYaKY*PTqfiT4iJrid@jvl)+y(KeFMxqucl6Vbwr~HSc~@uW z-hIn56A%^mHjLcND(}Q`pv z*7wx*&S~4XPw&`{`*uCK{3u#??%%!7w0E9;X!E(Uv-R6Q`t1IlpQ+#2_5SjOYu5j? zcvjZoO}MS2Vp>WC#0MXPvxDuaO_+aVcVfuNN!iGkA@ujv$@auhx=ns){;!*rtUjx_r(XnZd zKRqdM{yV$31U~dC{@4D7n4j=hM;}^#)%7HTwP*x(PA~5>=x=0yU=D~sqW-(*%GJQD z0o5ds7%Pe3lJ}Ww)t*yJm!8_~T7{nOMggb(f&9DC@!!t!oK)$`agQy1?zyFpja%6} zd&?>0i~nx+1&-tY3dHhM=Li#f#nfN&Vxv!C{ zM}pn+??2QT)cN6#O+kAv_qEQ_)x_j@?Anjs{E&Bw`386`$O0Oog!v%ir{RNOB9M1# zL$PZNN*Rw|#@4aub^P);ltOKHeWRr=QirsZ($&HyVf$G08k>#UR=i=Xho0XT_ydnk z;p9Te?3@q?8kS?h@Xu{t0!GWDSYZ$A)ZE-mt5GU|99X8Ng@9b{PD%rDI|Tm!-1+v- zmedI!EX~|pRhY;vb!hlnQ&{4HV;f@<64Mvzrfy3sNU413#e#%D5nmawwr|Tjvsbl# zFlWyL)7GPTJ3n~<-zc0nJImfF{C9nG*df@DSvz4fW?n6|E$KtD`suS~t;hRO_m}3K z_{k@W(;g^8^7C8At-}Y8Zuij1Z2m=N2&@Yt5hD3CZ0=0McFs!jx$TO7v7-wQ>&BJc zxHOlFnuQK^qeDj^trXH`dZp0^tVoAH>p#Y#sr?r>8vpDLfI?{L=7-FBXg9)Pp{JSc z1~RE*^=1j4fo$`aR1lYw`J-$`yMcj>c(}s>0{DAir>w7>@k5;PWb! zicg!iz4Z3;r`|fX1C2ymrh@7^4Cb_Ep`|DqAHh4O;#Trr#jQBW4&bxJuxIu**bnXoJay9?tucmd8OO; zik0|KruQ9Ic0e)gi?rUls`naam^r)k9wLgpOMnp;44Xjf1$7s81~Ks0%+~2bL?O0x zCO7K(p2LUtT#w3S(rqD<;j_m~d360jwD;ipN2iQ&(fCSsX(?qkm>he@m4_aD&~DGf zMeW0ewUdKdQ&F>F?lWfYxD91V))E-`ex@`gIGqVb^I(V&bV}GIO! zjv_mLEe5Ynj(7HU98>01*L1w#u73NV`=-onNXe@ooKxAja_W@P%DGJ%P19WE=qXcI zHdf{guFp$pm^tOXj+OiJ!&H90Z@l5_rwYs8x6)PZu6Hsu=vYUuGd_7pM@@AecDSpZ zvgGBL9fM2;gK3c5UDs5#=gyZ|(FQ|wRx(+VhNPZC7`nffP+cVYmGlvydlL8?*0*-S z?(u8c9&!;p(7xjQ%()H`eSBdT_$Y8`u)!p{gQ#R~?&vmu^VQHtjG*LOhzY_DorI7p z5H>kuZSBP68`8X@k??^}l92-B9>}HQt5}665yJR+p5*a8!vs&tZB*)IMe>*Ht*<75FUyxoA3dP$JvYRNh_)|k$8EzJ*BN1JFug>EyZ5GT#PcS zt1~mJwd1q3VWswba-KN0Fh(1Q%E);c3e?6Fj!h)z`S#K)HXQI#0qJ);|G_#^y33lN`_=GFVM?}G23e1lF zu>QUWVeWCy=EZ2aMUNM>wY9m%_m@VIc>F(G{T{rJ%01ZC*4A~fWX6RHGfMD~#hdq_ z2#ww{os`4VdHT@W%xd&rVbIjz#Pk@$*o{B@uyL#bB3A`Z4Jv#Ok!n)IAIO~1NRIx-qE%X--lMx*fl3%@Cig;td8s!(2fj`! zE;?FwzIt)YM6sv>!dfg#f}(h9NJkUh>SrY4kp=vOu;BK#hm@HV=!8XbBC z{&4wf%)B+>5VseVu-8vy4Z$L^E5Lsre;j|gW^mE!k9Y6p*Rt$`M6dSnk2KiFZ6s$R zXEyMWO`N@)eIRQehCOcg1J5vmz=7V#_DB$MM$k=xF+ks9yBIsd>hJg9a=;o=V4oAh zJFNQKdL4AOIK(a>0saEL(o-%OytBE%AY``yCxVx#weIkP%JHCSwM;LHX zO3K>9hu5a0?A)^_Z(eKbJUEtyg)sXj7#~i~5$oL)Nt<7JzE`M!lV`C#1L=q88 zc&Rn|^yz3TlK9uEt*Ef;=={l=&5nr?Q}RcT&Yu#oXR~JV{G(m?xK&;2&%EJ=DcLo0 zQj2o=G5q7&r5iePb36OauJ$+ShVrN%p`=9(PE%%KVW!F1kTce7HfK`2Aweep)z)aP zX5G5HwQF6M($ljU%BBHApH%Jb_QdUhzZm5?`)3NSD&+J2BH}5&4;7Z6n1E z$+pC(EQwBI6d5{efA|57m>eN8ha!pzu?P%inrqTC7Cl1xa1^1ZBSTSGB(0C*+H_oF zG#zQ7bq?eRp(sCppP(S0fE$@&BQN5OP`Q=+xGq{9ZnmXcW|isv^(o0ob0f3~xC{bd znFL`PDiVE;0_DbNUUY;apeT)>TNo0I8Nkn1YYwiZXJBCOJpX7vXl zTp5I24My>@G&+_UnO0pPtZYv0dnF@M?VnUmZ($-rBJ(SPxFHnHQMQ0|WI&V}?|( z4ycU|1R*-=2~`BfKPn0+AGx28>yk<;WAh8xax+xz8r3g|Y5if*M3qpc|gc?7oNoSO+#6D7mM&u)Ae8e3_OHz1*yi_6= zgr+J*LLX6>k35$ON#n^B(!lW1Jc}k!9s-fhoU~jj_N8QceVQpWFi;>9O8gX3N~F;! zg3bPBa2^&5RC=YKHl2x%wbdG;2l*7m7-j`J>XA%IWdvn00)^NbkfiVp&=_^*km$X-&Wgi=Te)jT?c;*0%xR4~o;f$eF0)QBez5lakGksp$TND!$oSF9Gn z=w2k!3b-NMCj?6V7MX}ft2ItVVlehwT9Z0HKU>WqqKOuA26Ku)U*{l$jE%`|05)}Ne4x=9hy>tz zj|-G;KF;G4-Pi(ixjf>6M=n_QLKqA0)$5Z`!+cwu7C)BrWzXKWw!J-H=HSP)aklxW z5%cF%Rm~yC#^~1ij*j})XsW9%K3dbDiH>jU-ntcitNMQDzy7uJKT6*6eo>4fDo<=% z{oQZb}lIrp8eZ*tGAt~Wb&(K&#r<4cQq$jtx3%;&Y`VqzWQp-)u<;{J)``YR*{BG>HFq4`(xsoQ^?c?l-}g>MPFIoPWcrpl^vJh03w= z#P{!5DIf&5g--%bYn`CS0ABRqrwnq#+fd<+QA9yR7h;5fT;Az_ZeoB%+HP!~H+bfdxHiu|fdGHqv5Pe?{=0v7gLAy7-d%J14g z7Vq>}BB=U)1HoO*2xw`}sosi;-cvatx!YGXH?P>9>pIf^=*u4kJ&n6R@-l7DKQUK=0H-_y|w#e#PSdt^PkT8UB!+e7j`i z8|RU4`Vzi^-^pxKE5@*e!@wGE&&bS7X4AcRb7P>4|{q!53Sg_R~hKT~CNkUZF}i3iJr(Bg!s{GhP% z@$e*yXlt9z{R&7`cuU@hVDCL8th*$h<)NUHhrxUtNSp!vo8}uVA&;{bOZ5D#rWXEDUn?d5Fc+z(Rq2{4(Bo(-}Fb$O^9zQf;j+~+CdTE z{#$^Cp;4#-wZhh8ov`9|A*{IFj2=MyVSlP;LDM~lK0u$L@6k`N6#FK{p%6u}-0V;F zTZ`tFa_3P4d2VlBR(boIN-qgdqa|u5SQp{PsCH=C3oRtmaOT!2m24WU`haZEo@V%g zwr3Nq5V$4^sS}}~{@g@K1zt>4OpwX!E=ZmSAScd6k9mB^&3`6Yu5!i(-8nwprLK5l>pyRQx)p~epk(vTOu1$-JmrHEj}U2;bocrO~HRdm30aD zf(SlO?&~KU?jyFA*FP?bOO+%wi4?*U3SCo;Srby*_<=YfNt{;cYYtaOpAxAw1)@}~ zEY!!EButCc3PgN!^fsQj$X>8gp-<#5$qfxG3{e<^9hRYr3KSsFDkUkxc!}1+1o_F- zDnYu93X9??7@LiXw$ricOq5-a5arM6hJJpC8v@Fr&NV7DTWk-Zp0`ADBP_0XI^P^G z2n~R6cfr(KhIl#-)XXpx8hJQD8!X6qwRcuk-p z0u)H2Ja7S`{NfmWBE>Zu1g0t6(qw*`>q}wtt4!MH8MI%hStRz8Y|bt4$;3Owdn0@V z49`~*zs$EWMHj?~Eym0hBDHy>)Ec3RDsDZ`$b)2DbWS|d78k~sCODGudOA%OkLbap zQ=2P=71e1Y`=*G?ll;|@^lMH{R6#`uH>e^%G9;pJt3hlJ2#9@Gqzbi26rq+4N~@2G z^4ICLK00oihi~0QD;0`->`8eo5z&L0L9tDT#wG!sGl740AWzK>z{~3>o9X$#Nl#uxX(;XD zF=Y3U&AZoDY(65D9@)I&nwQ>q{izRIOr{pz=PXQ!GYuc(uYoux#PbvMJqV4VV6+Bj zn36=u=pO($lnQ_mKKwQFyZ7KB_Q`TOp_wr=w$pKM-t?NrB{vZPh3lFH_EoO<=6O8o0v+qb`k1eG5F%uDcg{%lyg zP4=V*cZ1tM{Mnd`7r=*$`oJf49-4?7@GWjyN})X-WWHc2SL?mkX4|dN!ag+0+9$jNw<(mFweEq~v z6Q@2jVn*@2IY*EDr+CJQho(+Mm!F%z@E6Rm?b7!vqMmzr#w^>$S%+tIe0g}*M%%0z zWS*AxqKQnmm&*U93nHe;hiyW)HV@u`;LA*8GD-exl+#d?ySTaK?CjZRTbdW=*0j`h zBg4VcgUHZb*W$W&Sz79{zd&1yCeEy$T3&YG%$Wma!*mJ$e_m%Qj z5U;ns)-{)HqyI@~4=)%s+QiKov@)c*a>d~h)ypfJLskyT;+jT}T5#{HWPQNc7T0-q zV{yS>`Luvyp5Um!dpL{J;>HMT^@mDApU_HS-xT+L6A(xdYR)1ErZdzk1-lD{2Op&S zu&J;pkm12fd%Y=)bsGg;1@bZ)pjOy64#?OEypAVzr1`|rx_}caBmBdk#ba&h!uZr@ zBE#(wS6!iW={WX%!uWClZ~|LT=GQJIk|T6+;Yv1 z9h33K3B_xVTf!nI)}^+7H??NT+zQoWYdSy0qyMvcy1&ny?MSeqxx|#JO)eOFainc% z>)|nlX{uCnQ8P<>5Ho|?4zZ%Ze~q932B{vd0q)h*_GPm+k4ny5IP;zv4rkKF=IY4! zs^zVXam;J|&vMDLMuKT}K@*DNI0Ha4jw^x*dd+H+5Gg% zXPyj=u4yldk&4j)^c3EP4=uOwJNuSQIlXF3&PZEGXkc>R2MD~kJ>^pbhs53hGvRWw zSBO<^a;RxJBc~2Iu}$qn=hRMI1;k-q%u_M{c3p&@zR#$xS*{gq8KrRRM<|1M4FGO@ z5%{Mv#5xV=C#v+EKa3CVSMdVz z7BsR6Pe(n0Jkis3*>--oAQ zLPHLoPB4ygFgNnqDu3MND_pMAEf+$SKO$h~v+2k%kdE|hdUnDa>GI`LUB=lTWkpqro{>30Q(y%@7$B zumv~Bz7y<9Fq+&6LJ&Sj2_xxH3)vkrlU)++G?9IbKs@qcp$UvEf%QWWYFIU`(J~5{ zyr3C2%B0&+0T(VLc=!GTtQ-4+C zU}ZXb@Fm|EQDz7FiF!<~tZxdf#xh6n+oo7Q0h;|OiZXwQmm$uP;`Ho3>9C~vb(!y? zIot!eY1jyJjIR`|*U;jRb0hl9yr*!zNHl7iub(U6SMcOgVRfzcdG5z*HNG#D3DP8< z!=n%%Z5%6*^Q!j62KW8TG|KgB&F~l#EL?52=n5bPoGZ9OqtD6`U(DfZbeXtBX%K^ntJ%e~WuWG-akI@qr|fKR#k;R!aPaeq5E*z9 zyl=|;dRgaCs#$^>xne2L_ELb^7=ephBG5{CkZUYDxzSX3lJp-gM~2(@-}40EmLdng zUeK9XM{MGbjTqP;4%!YJYV1~6v_w=WtK15^%36>dOsdTHIOj4%q4{+TnAm2_rZ{~U zT42!qTnjY@|8oqs;b&UgQv<`8Nn`LxR~WkQGJ0+{K2Iqq*!oa{E@FEMHPhAo?Dal~ z@d1CYP)rJ5UxDI=Ac-OhC*yI5Iwe8Kg`ahO{d-uAoajG+6}mT28@rYt$nP)1I}*3v zY|1U9ht!_^9An#GhPdpxrr`-w^}FUjjO%ZM_;%b{!9VN|a7zNq!Qy|QcQOnxf)~o| z;Hx!%72h?VOex_F89FOPUQwcSj42w*D{nYArUNJZ#hScvKtCmJxLwSxVkFk|xXJoO zV>G@p*AutZiMfqlbYN@$LyBR*7Hv1!mEPn6X6gSyF{1}}ccGZ? z7c8g;Px9wnpL@ZH9{T8`J83(LtiSy|ZF|N;o)!RcM?Cky91F(4zewlhdFjoqgZV=W zW-U=S@X@rsSmmoY#k&S~0sq;0YfQ-0*qSm0LXmZ?w5!Rh8bI{7C)a#{43Soz$+}iqnEo(M_O1vj92;svwdHrKP_-@b zIh)n1iBa~q^QiGu|o`->n!(3QW&^IRo&z`*0!@fQ9o%!j~{1Hg8a#LgoT zZNWsMmVw3JBZpzM6NL~+Swx#y`Hbj(scZ(Z%(|edO^GHD!8A`z-xADL6Oq(JOdELH zKgCOU0aV%B!4C9&b!bzgT#lmV6&<u@b(}H6NjG2)M>amFDCYVHFyHr z@ipF&K|P1ZTtyA7?KjTgjG>(}y+4XURa^-&3nPT+9Bk-}XGFB1CnJpJfR}7MshB&n zZ{o>9(?+s~muGHG1hai+=nJ{vsoDVJlv@jl^&H~=_6H*kCCrKZexSi8BMt4Jk2I8? zk%oZd+7ILU;jRPJa8MQYQ&qUeS2ki~a5)~75cnK8aLG~CYe*7$8Xx>(SI)G)j)KJL zl}V?dUbb`xE~og6&(W+!Lb2%8bW`7Q?moOiC@gK2Xs-Hwq)GV|=a;Jwg0Z5?wVy2? z-s0N-h;PheXkCwQ zI<&9jGra#)QswkS`o4Ef>92}lvS8m)O3bIwA^VN*nE=N}epfY;)>5Gmb)}*vyy~F3 z96fU<78-1o|XtWaW;Wp2Z}9d;k9_;ZXy z_#e<+0GHsvbIU3~s1?>-c-d^(kuuD@^{*X|Gjo2nm}x8R>ZwA<=_7PqCy|kkY(M-`%zF3zHFFSk%39SJ#5v^f5*ljW6ulIc?O~%EGBD zGNz3z8-!9umQ8G{h6F$hOuhQy9lTGNk6{)+lEaZ8+CX>}h%nZNRtetnT7wc+267?f zgx#iaTbaltC+`#d!a3KG@u<0?cw$ST0oAMU9$zZvncaBL5d71YZ}DUIF3|RT_2ABb z32hyenZDPDs+>HrxNrg&e{ygx7A8Njcnd1~b`uf|eRamc2funBv>s@uLVTHjoOuk+ ze88R{2X4bLfeV4jz&9`k1iCl`agehsXgqN8kK=~x@symYUwI=LFJS`E41754dM`bU zERU$k$f(icmzj&dr5(M|!Gynh{lQ>n()C{IDY6nGy%vn7ygzs+>_T|=xBe9f(3AZT z(6;`wKZ1o@=7FVeO+QflKZJ?w^LJNVcthoV{%1HEfDmo%hj8HRuCU^853ILN2t5h@ z1n%tr1^I39hREtsPwRT8|5+`#U-rY^cdq|z0OJE`cdbvxoo&#c0Cf0!nv8&zC)u1K z|JPc1x6S{xh6C+1aP~LrdaLPfo!qK4w59Ma^&a)VYEEo6{cY%7+dn(^&i}vLxxbYM z>ib9S-Jk2O?S8B3sP;|@xRr7%4~$X0_bMQEWUuj$x74P+>i-w^BDm0)o7+eZVDesj z7W~n61MYl{M8~=v7BDFO6=-gwxBtCM!Y#=9{QfqKo;m@ntZn+%9uK#{>FpZ(draZi z{`{@CFhO*O+i~%yZ}4{3z1!RFR$I?|2Wkh1N4eA--U&JlAmNaJI_{XD)SMTHj2*ZK z<7jf1VRMj(knZ@9knaV^$>v25L!40=l;g?kj#NpaRFZ=(WrJoyJW{WGB6q1I=Ro{U zlG|On`KQ_kjfa~4|ZeE){ z{f8g+QZ0MKlBREksi+V3E}uJe-6x3m0JxkbpnUqpH(l}k7fzpkmFXKn$1^RB`B5`m z=uk}q0P6K#HqyqOZ~ddU+*Ty%Yo+**;AQ3}=siP0^QnbmiFp+atUjJV9bmR|vpk5U zK*o>YGe*=rw;a9p`Ihya;miS#Bf-nHDo6H^ z3Ooeu4H=shuEUe?7x-allQqKpp-!gIo%Rd-5}iW-@L4rz z3@T~ye{1wwTsGpym*PylLQ4N8#dTxRy<)jO&$R^)8i9^byB@eWYuGPyz z3Msm8JgygKQY+BW5jY1(4f;IHx$wxGi#x_IZQ(FrnhHaFnjv+E<^Oi8N6ZsrAw)$Y zW=@MYL*V_mtpLA^|J?#{jo&TUhMwMCb>Fsmc*|wSnwFL|j>~wzw1At{ z{C{zOg|;ncce{k~zefXr8Gf*R1CY?DtXl$D3f-Yhq3KC7G^^GLE*tPc;IsiB*a+H7 zO@K%uB$eHXofHKP%>P$%VqRT(WU^1OrDUvS%OZRgUtP4t(rVr$OpZ*i%S%kID)0H? zp$}Z)bLJU`^+H5)*^^;I=JmM3FFtgwr@X2yE2(0~c7!YnXRP0l8-Ck&R3v2&ZH@{@ z{G94x`SsEKywKd?Nw(zhvEwF@P(72zjfqIMB@GWEBN#0;w_hAsqS>z3c_$t@(`_s#o! zzJL5I>vXqwySKYDJ3BiwJ9B~>;ufSE{JSP(HbwB+O(exlE^moLK=&L7GLR(LWit>o zHWNVmH5Yd5E+#YqI>Kg!rU(jrXpw+EhB#2_LqC`~gV`>($YEzl5N!u-3iJ!<5bzjI z_VHOjb_n=IdP-2C3iqG@Kq19HWnqcq?ye2>kOkbjnIMJu@OBw;Tdnl)^s4eGt;b5K zcwc`yORu-sa_>j&j_NN@kTdZI@l*JzgKqvoXpSsBU54fa`QLNsv*`Z&#L}g?HVfaW zRNt;I^{Ddlq+0*sVP+uiIO(_(8W0egmj{Z1j)mYHrsE_y9_(01?^#Dhhf;xV;cjUo zHGV#UC6e`?p@A>I+z-8tqdHfDZ@anfDjA&@6V|U^Sd8PWOvU)Emy`th_-QIa@m*?N za~k9gq(U8g{^8ktY6l<5GBp7qApyCa-&61K!((HGG*&nVSka<#@OkC~KB9a8QY4T= zuQr^R@e=g{ zdNKdF`|-n*=i<-W@Mm);ueH%GwtIO}^&p9I2>tBo31jBY>d4E@IsfQ$KBW|@d=Hsc zZ@jmjqIfKP^TWfJND5TaVkd3R9XGq@lAnHIA7%eqC!tL{^+{N?}QJVnVtk?&)z& z6KhLGPYL!5(?xg&p)4|%7|{s)2j{|W68vBF2i+&k%n*PQ!j5ugm^{tU5n#q_0E-nu zJ3#aboE)V5IF_$-_+NW1?S=u_CrEpS;^y((b18Q zmy{JI{1E1IKrBA+Kcr8@r@sFlpF+joe~*eo@arFbh+jwXAAX49@tG+V6;sF;W&hvH z`AhlrP*zX5y#>Dhp|iXx&@Zeg1dnss${qt-hZ2adG1zGp1U&-XKwwJZ{XzE#(is^b zt5qh1DkN#aW|ecY5zvNM5fVaV7hG&~Aqts(h?G_!Dsl+FEK5V2Ot3Oy-pPuI$s%9+ z<;p83-x}0EV%~6zW%#^^{)65+d8INdvwe4JN@3ijP;YO~i1;iYjm9S{KEl)6J9JW9 zVM^-m_DqM>rVTH&tu0ASE%`aMq=Zd#7MQj7@j+!?IaRG&yd5vZ#?tBDTUx7fyvhbW z?iQ<1s&j)TH=4|DPe~+CxtUFklY??0?p5qVRq;WEyd$$ohBwHXrl2vhrp!z*krIJS zs0lwN{(}7uv=<~+T(ZEE)rdxj+C;Nqm%=j9I?;CUn{Yz(9IR3mAj1O*9SufNfJo4b zFz7*!C&=u{Py$b6uuYFl;5I~_gJ0MRNfhNOuQxqAc z&T&Y(+6MPYrY_5OG7^O}uzHSRJi>udQ(}c(OPI`Ft zwo8)m#z!`?#mJU1lX1yLVQU92_BIuzA+6*6xzqgohRyOrS6ve(mA5?pw1>x;eQVx! z^=va#OC{2K6((lg?Npcu@VKQ zQL*)@srBS*3e^XMfLU?0(nTLA2@FE-T~*;FXu8ik+pfK}?V2x|jTicc*(U6~`Zg8x zyz8vJBdhnK0Voo`6OfaK@8mwCwinZ3_>G*_geKGA6#Kigo~RqKYqlGGIze4?pd!Hy zPZ-^3E{G0GUpB3#diFyFw$1fx`YGZ9(mf~8i`~s}Bj+C+S-atK&EV>q@fibnet7Z0 zDtV%RX08u@6ZN0BwRG~KdFLs&)avR~_#$7moHmD{7`4((rFWMAkD7wt7w5385Xt5m zp~GY#Ikmuo1T>s*mGQ zWARJeX$zFS8;5|_L1se4;gtkY;c>u9QeLuP?g8=Eg*O2$bmnp92RaBDpePl*l^AYV zA;K>dF4UNCRW@7l^x*ze z$9a>djOF1)LxxO#;^MsZV^u>&d3uf-q8ht?-o=#i(h>Vc4s=cCveFV`;V&^Qi%WJL zIC9^J((uCU($LDr3^VR%57UWPEUNe4W-y5im48zc$NOQ5zXqTVczp%}*a1pzzYx zk^3Vxp~lvIlO8%TuCAbQ!TNsv)-Px*s2g|Uq1J-D$CjUNc{d)N3>n+V}e#2Kqqiyx-;f_`T-jhdPjK@*G2+M5#06{c$yTu^EZ-R{-c=u1SL^xYbFPTdXn(GK$hG+2m;1pyL-uNI_ z-kTph5h9{^rlB11b&`GcF_M3#P(YKA3-UX5kb(pogZp;Deue@V$pz1NItc@mUT>y@ zot)8M#Be{~38HV&`HnM=XXz8UtX|LNvPNA*gwDuhL`G(iZ-@Bm-L>rDd)169zbG=A znjQ@f{R17d$=!&I43H(1;Wm1bSW0$5!a^R=YB>v=80bm()8+W1stIM7xcaKYyXm72 zwHmKSFV|38ZZfkR*995EW%dsSf!@y!afLv74D^QU=`3-nlPV3GW*9D2QFW3ynK0nbMt)RL$SV(XPui9e@WQ8@WGJ?9NUEsScTqfxSg$QdQu^phevbnc8kP$sygz!kJApS-FtM z#2g8EY(rKLu&zo&5W=IoL4*pzEa-l;_7v1&{kP#E!DldrCJnA0cofY@JX$*`A|%*( zF}q_;Kp?eorvB8#H67TkW<<>hnQ$(o7Z*^cnztq|tr6xa8{-Rg?m{~O+j^?Irh{}G{TZoR4|+L~ zs=HR?fe!NS``<8YAx4Ft;JMpO!U%NXkCT^&F0}V{W7mt<9xXf+d#IXVMmJJaLqZWC z#&1HwP&nh(Jg>33alHWeE~sySgn0mN##uq({dgT)FZKefwgl34T0qJNfJtO_@RhTi z8XP+cNG$ILtg}XJ{n592yW$k7OySW)G~;Lysb}@z!PQs)QnxwHc=KPo=JSO@<(kpD zN18~zH<(OlRNtyP`-*-E@XuG+Yu&Zp0al;5@-}F|9~ZbhR|cZK&LZfSoP9*V)N$`# z$K}fhz5r_AY(LuL>^%WQ8&L+nu(9zlfT_E8gte+@xp*JYE$2H~E3q&$5N}RS@W5Kk zN;W_DU2%!`br;mPc>aF(YpFbEJ)A&s)~xrH(9RfWOb%zKm}n+2zYfM&=XH;I#^O)!B>G!dsPr@@@7}JHy zFd5OLUnT3haFzJGC-n+8>-u7=j*w;Nj7rF`FrW6qPqGgB6Gj8Smk=wVPvMHHcapB2 zadR)ew~p}C7Y79D2h$2UgA)E$HNc-XF#5X6kX1g>*svy3Y9#k1Zj0>5BWi^=XDH2O5J6eLLm+goh2w7pbCK3!&kT8tHD1adCk35P1D;a4H`Uj;3Vg9%F6QWoQmb`{WHCo z|KRU_7=(H381y5r_R8u%yEG=)6kR49g}w&(F(%l?tcSJ&Q72}|-2f!R2SU(-&`20K z#B&27UjDv~x#MXxTHIB~(N$Rp4n|JDW9^qP&^Pav0z=L21+x1YX# z{pq(Uz{k4#GsFX!Z(%(tz?Q6g1b|8iG{pn>aj0MnxMDs%1{Lt*sCD>hI6;MwM6E-= z@GqrPNy4F>N=oNnq>|J5m!KJ>TwqY|F`tsPNhl&1A{5Bn>uf-;;@Trrsn8O6jCp79mDiTRYi z0~RtuOTaJ-K1v-eoLFScr~H1LP2a&;=*Ax21!c73O=uK-$KmoL8bx8ALZdJ&B;7ay{ve|m1TwAGzxEvorD7I*MFx|A8N}75Ad3L3CL2gO6$zF> zWECJk0(m^Kcm}Dw%}yj2b`_|oAY6fo2<3%yI10~@V2t3KcyeWOHRicDkRqj??0CmFDEUY|6Vz%hieToI0^zm6i(0 z%Z{itV?Rz?O1|7AB;ordT#_wxpz{CM-O6>EnM$qkgWc*Nz>A z4-ajbGJb@%zAAMXuh5R4((-Q0Q0;g=BX!tVZ9Q5#WxRH13qCb=SZWoh{K@*S0I%bo zhB=tXJp72wB=K)VFdliaV8{Thu}s)|ON4jb!ai843xtb%`p!CT+=RQ6nVb0R7oT0g zXO~QU{PC$v-p#dFSKD**5-Tba^Pv3kcd&Tv-SI%zf5^sxuPmi4*+{XguC%o7aDTH- zXYOAV5)>3d>eK6=Unclrii8z-Vh;v1i>8R$MJvH?&uY;ch%E{{gAj(>2pi{2FyW~g zC2b|P796+=mf7S^aTY^lQ$S~pNJw?wgCik~kZyv&E;1Fk9qu|pfX!ar8Y%Q|%_d4U zqEmaYJAl^c#82Y?biDFP2ZTY;z4pQjuOXe;C&2o!UyyMd{^dFNgHT`6vllO(MN<5S zr&dv_4bx;*mM>bnYkE3fpo_LnRGJmlMn7id^;LWJthx@zM^|4rzrJG0lI3r_v78+7 z<-PD{wuNZ5AvQP$1>5NbPG1se@0t?3y<`olTv8Ap54!Lt-wRY?9A1Z5H&^U%Lm$q~ zii*mbyR=_iTtAp(f#JeD1L0T1Ec{9kCGo>Jz=&wh9rGSRh~d1jLlTW>-=Oyr(W!MARJ4xBv-jDy$=o2u+=!g12Y9ny2|21Y&ZGXiq zK5tEl%?6lO;rvy;r%_|R2hrZV2A4RTy3vJi`EhaifNwM_#+dd*G~)vJ2BDf5Kug|D z4{mA2_&yDewrIdWJ^-Ia6g&d%Ii?|s;Gz`62|-SObPO@>fXnU{L;+SNUy>UWG$nCHLMxrVb0m761=VvALg?GTjzjf1X-!b zY*v^_NaUYxjO-#nFoS^Ak8lr;U8n?GPYL5k3rCP~LS*tjDsDoXY~}}O4hvdMq8)iK z-AQBW>z~kSyuzO7!J95xgWnAF^3;y-k5tCD)fPXrdB@D`VK~s{7Z$uy5fT{K-rUUe zzrOlWCtZP~*-25zamDLhbj2PVK^sVE|~9Q(UVPz3A!i4z$FBEx67&?o|+ zb&eII2wH+KN;N3b-xdGh%ArVCh{M6jP=vem*YqkBQI-DOU%(=e4g)dwaZfEk+&4xU|D#r;(LPKrQ7r!Y)s7Ab7KQveUVXI#`SE`a%bvMo^Fzh8ZRAn@ zNN|{+4Shjyge3B71K|(Q14(UuezuieSN|QdP;Fhv5= z7XfR|lV4iGAAyI%;o(DY9nQG?;lwb-nqs@Xc+Kyw{wP8t<>!!_v?SZb6-98ad=+3? zxJEid>fQ&zcrU=aaLyIqh2(H|=`VnH;Z^CB>0crqH5L$$fhdLB#80zEk8Ca)6kYV(N+d%lemTf$(Fa-M zz-+(*rc-f*_Y;YDi1QLCT89`20R>4;&WBiJKx^PgS|^-HHxpUd~PcC#a?2rSLi^jpTNE zV1P3K8EG=nMnN)EST3l^g>oQ!_b(_!$xTa~i|BUli4m`>r4f%s_%!&8DT;UZv&CMB zy@E2RP_4x!B!+YMX_SP-O5I$>xJPAk^b&Da$}*S29LmcQPA`%TGz{^yyEXc_C^?l% zFB3xmDo+o!hnK>`on;uQw_XWR!qmD#I$kW5*D1V>i6PYs2d{B8M^{eqlY7?=9x<{s zA*;sbvnIxx=QrM%m1H$)gR4_KJoK*FE3zyJbY#9|YE*(O#?5C~;(@qAd)T$kqjgIrA00n%fJW_RkKY^U zDi+hyP?=OB4f5tRUM>>ftn@lg;vQfM&!hU4P9JP!65Nx+#O{$ZYohwac=*#%Io=Y+ zN=4KC`QV8G|ISgudoW&pr9DH$N@&9osq^F zjQ%MJkwIEUsw`J}>+JGzvNXn2KqYRNU2itHPOh{iFbNsCHh)F3LEYk|H2S&(8|5Jt z#RjD;f$??qs0t3vQ2Qju#aAa%ffl7XKB4&5@|=FnY4yVwaSFM&-or%_=&$#c$3{(= z>g`<^85u0jokpE$J2rVq-C1cyP6mF-RY|2MM@JcuIXp;LnTd+%_=p6uRxyM9{gH$$U)CUIEG}9WcCLu%HhD>P7}=&EeFna7tBg0Mdw5>i>^Y9v9Cn8M0XJlUJF1r z0;*~&N(W&`B^nIgMJJ$H=wTRzf>4tnwz=nw*h!Ib3C1@)XT52?XT5j->FnP=_fL8M z|CIJ`+tK@6?^$m^|u(P%Q0E(RQD7-}>Lm)mu*YE0ACJySnT1e|V<1fq%>1bE~^A*{zXL>8`;E zgA%%af9v{1O%Eh=-=NlX-Ef@hI_XLI7mxfsQ%~-D^$(WUbL)RA*Wb(e7gg?lr2Dt0 zR^18RzujF(Xp&6Sh_`V&*-r$TqyhbNG^}DWK!R2w_~V%Y_Jk{iSWHLAY!3tlrc|)B z5F{Efo2k@YvJLV}7#m0;hCjknPT#g*YuNpC&z+w9spmPZdL!#}R4PIemQh{BHi_-^L z@bWl=E;d#l6we-18KI08E0kh<-)>L12c;{5jc5tU!Ph4w*fCFDL8}uCYHN$t4k5ek zdSwFsS!uK<1a)5hJMTsroMn8K2qimne`ScX2I(zUVEYKW20LXzt}LvD*gAl1G1$^J zfG6cGuTT3BlZvcoWQ?0xtM?Ay#9$$_L9fmyS-`u zL`J(7KL6|d8xem0PaGWZaAwX-+ttDfyqjg~{_SDi#0_24jWPfaS1@>s%atAMe8(iQG|PQqk(&y^;}q3 z)*U|&geHGxP`8Jrrq%IG*0B7`uVfXvf#U};7ve3INOW>>H}B@+;tmdS z^G|n?K=dl`a2`GgXE)$|)Y$>MHO|Fm`oP3*@bNBAc zx#iPk?_Xh$ux_vdk^mK?B_Nm5$t8$A z(!{^Wzu3gQ(Ydz*eT+V4-5j6tUxGViT@ybEr=m-slj_aem9r~T@3VvsGotDEJhz0s zB19A*vHb*U>vRL>bowU9*opHqSl5t^Gj`$*O%2K%3B@fj`rIAiV>J4RAMr6xzxx?` zN5)sme0|ALMmGZr z+k@nbXhM;NHb69Xa7aVW#a4WF9?F}C<~e-l(%z@7Q=n+$z3iRh&YxeE0X??_RE;e(xMj6?LZg zx)v}6d#4Ab&-(i7S?NJ<{Q7GIf00V#FVgXy?}=OR0=$49wwDE}22y?_5XMMUd|803%8eL zl~OaO?oz+kQS#dE-MXlu)OWJ5fjRZ#ievW_PTnQ+q0lw{(sAl1$6;M@D}UgC5>!vY8;75_jNa=WdWB4Rk3VxCM8l zf^Ru5r1=spR`K8AmXpU|%hYN9QyDB{0#V|-=y(Rc^jg0}x~>_|BYorsdp{O&`^C<2 zMk3qifku}^uox{G53>JhPzB=tpTOP@VqWmb&jHyc7sND;*vP>QWl}M619)Krg)&*= zBiP(P7UwFkAqQ3id|kq5f_~=2u(LrdJY`D-mcxRAjb^Y%W^GWSnruZSAGM$ihWG3b z7~m##?6c@X0_m51qLkqP6z_2REIWVPHp><+lj&v3uo&dB3oZ5Ey_kfYURGZ0$iTyE z0u)OB8lGRVZO1aS1O4a40=4|ua(*#2qhBSGzeu?>;fwAHb|MN zb^MZFU-;#hi|Dt`8XwD=9XD?5SYz>_+}cLqn>+UJ-+`1P+R8(dN7g%G~K>v{XA zU3;G^F2O$V3@Ec^0 zgPjmF8@Ii$I~n3$2K!$4{rBgAwBfVsH!zM34mG(JDA{^YzV>lz!+&*h!+PPy^S}Ro z0X_Bm1&4aWdLifYA{Kezo#J0u2WYmY!~UH8q6@%%d2vADf7$@Pup7wW5H_cB1Wq#8MnNQJWUGZ*V6!0_5j@=|l`!cbW+P9FfBAXZZzomZL1~)~ zP=(X_1uXwf?71-B?3gxR;v&zLut*vn>?UUNRbtoqtUS^_O*$_*@;8~TDJo_@$H_}T zZx|dRWte_G63KkGu!AmMUWTYm?<-t=eobK^_*rH(0Uj}mTAz8z62tto0`)f5_2Jp33x&@zm6XfBdT~O6EVv zJ&srYuJGjg4UymZMds>KG(wbg>-PacO{I5}=oA8Bjw#n3cow46s8N2M%?KFJwR| z9oc-Wvgq_=oGN96kje<;$!mjw2u{b%c$hBcq7`3t3wU_XyzwzAWY0%(v1ha;5wG7I ztcyYODgQ}&w~LP5<(GEt!Z$DYC!$>%+=f<0#9TmhzS#e{#Zyk1WfkZmzmHNUN5?lu zX?(@LBTOE6`~}9N_5y5}ef_b??bWI?(965Ou+zCK*_d7>UQh7$LV@p5)-KsSj zwRCGhfMbgm|JZ*F^$YJYra!()o$rsL@zwrgcn|6qpd(D5x~N4##7^s_5AQm6j){ROd)kEy{LdFI;8S3GaLoB7evP`{b%1+T3lq}-@7lk==WPvm58yeV%3wKU(CGb}Mx96Py^lDt^ zkUHyg=j1tnL-!aFLrWE)afSDi>0Ad&l5l7#v^n0EjKCO$s06s}3x=&jQ}3m%8@2#V zWiR4oaB?pVFN0)e%(7w2mk(Qprrvo4elVOY0}m}^?98~&a*JUvoQGh~)d%Zf(10^q zZn3B1iY7c<ZWBjk@m|yuC$341`I)nz^ zIf-sTn^>@A+|BJ5>LP}kxd|S`!D5F49-44sG8S-k|D97@@$Gw?sHf;Gz6gKK7qNfx zMR2y8D{kV89Ov0ld=d53y-h2rr}!e$SHwoLyIfbo4+>U5gmS@Ne&Eh!!l_WMRG3oF z@T~GReBj>A*913k`J`w^9hqTYyLXevQ&}Z!*do&@sWWVI<+jsLf}a6@7;#q6-ik~x z>yZUHfLDtMW5;y~qhPvIfjb$&%o^fv0VedhVKN&47nV{yLc!DVZ|Bb8-;mq6bI1+9Tc4R(Pret)vlX{KMg>0T z`PD-QAvHYp-JqeXai$M``eX8JcRptZr(GFZfL|21v)@1))xvtvxkdsOL;!G~3U$qo z@ghR>VQVPNT;6>vFCH;8C#RtyCugW*+Th&WhG99`L+PCmhouwWg{`^Czdq*4wAZbB zaxebw;sx;A>U-f5QZc)QEDa5Lxr2x1<}?g<41?#FKol45H`J`5V)?gOwWR{TbNC|i z#oqvV{01!R0ZoA}T?an%sjji5fZF>J8VoMU;UDQVh}EfGDP-1xZ6<8&)2ZcV8m9CY zKO~|9I8Ya1SA98tFY%N5dK6QR@0Guc2GnoFTkw0g-`!YGEAcRX7}|x0QM=GCYB%37 z{V15rYQX4n_1(K$?;_0@bmJ&~dklt=BaEG{`VhMmr%fEJr(KZ&ssmQGf^TiwPV3ZA z6%b@tXgh0Zd82ynyYzO)M=g{e{@#pA93Pn}znYf2eCy|C{u=$|0AMdHbKdxzq6)wX z(`4wW1I_uP^#LjJ&&HgmkVjETI=%A!H#) z0FhbF!s1WI8DIw|2bD?t@IyY0O8$^ahJ*C>Mig^95pTI&kKTOu-Et&0KU0tIC*DTW z_y%e>00)4Cb^)-OkB-5sj~*p(`3g1)-kpxWLhFwnC4EAR+VE+RC9MLhRV7%b5N<-) zPYpa7VfM&^379meOAaecW-=XnVpfsQkW4xQ5set6wI$e^w zK&=hd$5E=dM98c03=3*7a-3;s5dT}hEgD<-mVW+zK+AzI=!ZYyo)J?(LxJBh5qb_Z z7%b$iz~X>p3if`1)hlcWATeji;z-FoGaf&TW8kxREIsm@ueW{kH9dxp!tq7<6_x!; zzUJ>xdNdsG;6I_n7HR|v*#7FvJMicHBmB!~Qdx3>J*5mlB-(>-aYNX{T~R+^)+R3% zjyi70DLjWif#;k?^XX^Me0+;3MHg{K=P{-ey?`?XnBTmAg;TPn0!<~HT3;&K=e)0- z35&Lj7_nv3=+T=f#io%XH*FX_Vsq#FJ6c9;-aKN|7N%sx#*HIJZ`$Ngj@1=u>*!fpMkXpaRFvw z`|OYs>m5FY$3`5VFl)oC3CBksFZ6Lh0-QJ#MjV3#Jom<~T{k}2x$_g`SUB?7$m1nS zheKI%98MQ*crc-G*Nq#yc7E~+R1e@d{(b?s7V1ajjUuqU{agJ=@BY1pFx~d4Bexc} zJy^*NXw8Gw+`!-bpX-U=LYE(`DvH62dTL9H`u1h|f7hGlJ}~}&>)BUE78Q*gQCvLY z|DlU_7L6QPR6Jq?^fT}o+*`~Mn12B4LSYHo{SibOfE0vebP*pQerO*OMbn7F z?OWPYXI9sYEiPZCv20#9c}kmSzqrKllXWqX=tau4iFrqB{Gk2c70A9LNL6ccYU=2}s3Ht~yhGSQCV5q{G;DCxO zf5D%f@C3L3?vi*2Lgjd2w>eak3~d|T6ZV`te`g_e<%Cbfq^z_d!<$>O1Nx=ToVswz z{PF$0edLB*!~NZ-Qx|+Nt~hn^5ytf4tO*@WzWD*mrZYHs`l69z3?ZrS?hfFaJ@Ck< zpWPNRvmf#Uwz`z z=r%Uf#mHZMp=jRXHR8pSC{Gu>MLcuELrVxxIs@;6bZTFlE*Pb2TTog zT%BB))hv}4RZaHNu}}IHPL6wq%KGYF#OHbD(%rQ_0ea4Zp0jH1*mk!es(gG!FG2NG zd2zm*R5q)z6@iS;t+=3UNJah#HOqf=44s0I5tLOrYs~D;huEyS&68ym>j;$@nxYgT zEY94q1D%)1Lkbn1&CY0gT+%YkUtwd;+AQ%x0$H2!jD-K11NgMHWA>c4{9Fdeb zC7M>UH%rZk9elPSP^s~U;Gg)-Tfk)gBsZ8ne|#O|3)_#{nux7jKxSHcK)5wA%_HEo zYsiJp<#W8f+`Z(!?3{a9pUrDwSmf67&}*A!H2I6YR^ab|Wa@$>uJH+RXct4dk9dgG zl@W#CKgV5T^|1c+ft67Z)ED+Zayp8JIY=%{4*(GhS@Z}(SeSUZYc5HP?pd$q-B^)M zd|Oa�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 s&|F?&E&K`&RJ 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 H>B* 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